The problem starts with this: I need to write a COM + to connect to different databases. Some friends might say that you should build a COM + for each database, but not in my system. We are doing an education-assisted system, the user is a school (including school teachers, students, parents), we build a database for each school, these databases are the same structure. Of course, we also have a management database, used to coordinate the relationship between the databases. Each additional school user, we activate a new database for our customers, that is, our database is growing in number, and we have only one client, we don't develop different clients for each school, and our COM + has only one set, not one for each database. So I have to get it to connect to a different database in COM + based on the user's identity.
Obviously, this COM + should provide a way to let the caller (either the client application or the other middleware) choose the connected database, in practice we find its database name in the management library based on the user ID, and then connect the user database, where, in order to simplify the problem, We think that the caller already knows the name of the database and calls the database directly.
Add a private member dbname:string to the COM + class to hold the name of the database to which you want to connect. You should also provide a way to set its value, which I started to write.
procedure Tmtsdbconn.connectto (sdbname:string) ;
Begin
Try
dbname:=sdbname;
SetComplete;
Except
SetAbort;
end;
End
Then put the Adoconnection,adodataset, and the Datasetprovider control, respectively, named ADOC,ADODS,DSP. Set the connection between them, set the ADOc connection string to the connection database "DB1", which is the default value, and then in the ADOc Beforeconnect event:
ADOc. connectionstring:=connectstringa+ ' Initial catalog= ' +dbname+ '; +CONNECTSTRINGC;
The Connectstringa and CONNECTSTRINGC here are for dynamically building connection strings, preset string constants, as follows:
Const
Connectstringa= ' Provider=SQLOLEDB.1; password=2003; Persist Security info=true; User Id=sa; ';
connectstringb= ' Initial catalog=db1; ';
Connectstringc= ' Data Source=server3; Use Procedure for prepare=1; Auto translate=true; Packet size=4096; Workstation ID=LXM; Use encryption for Data=false; Tag with column collation when Possible=false ';
Compile and install this COM +. Then write the client program to call it.
Place a dcomconnection in the client program, connect to the write COM + server above, place a clientdataset, set its remoteserver and provider properties, and write the SQL statement in its CommandText. Then, put the datasource control and the DBGrid control to establish the connection between them. Finally, put a button in its Click event:
Dcomconnection1.connected:=true;
Dcomconnection1.AppServer.connect (' DB2 ');
Clientdataset1.active:=true;
Dcomconnection1.connected:=false;
This code is meant to test if you can access the data in the DB2 database. But the result is, click the button, always error, what is the reason?
Go back to COM + 's project, debug it, set breakpoints in ConnectTo and Adocbeforeconnect, and discover that the program executes to
Dbname:=sdbname;
, you did set the value of dbname to "DB2", but in the execution
ADOc. connectionstring:=connectstringa+ ' Initial catalog= ' +dbname+ '; +CONNECTSTRINGC;
, dbname again became an empty string, so it went wrong.
Why is the value of dbname lost? It was because in ConnectTo, the SetComplete method was invoked, and the SetComplete method thought that COM + had finished the task and would release the COM + object, so when connecting to the database, A new COM + was created, and its dbname is of course null value.
Find the reason, change the setcomplete into EnableCommit; Compile, run the client again, finally run successfully, retrieve the data from the DB2 database.
But in the client program, put in another clientdataset, after opening the ClientDataSet1, open the ClientDataSet2, want to continue to access the data in DB2, and the error. Change the program into
Dcomconnection1.AppServer.connect (' DB2 ');
Clientdataset1.active:=true;
Clientdataset1.active:=false;
Clientdataset1.active:=true;
Even if you use only one clientdataset, you can still make an error when it is turned off and then opened.
But if the client writes
Dcomconnection1.AppServer.connect (' DB2 ');
Clientdataset1.active:=true;
Dcomconnection1.AppServer.connect (' DB2 ');
Clientdataset2.active:=true;
can be executed successfully. But it seems very difficult to see, why COM + after connecting the database and then release themselves?
Originally, Tmtsdatamodule has a AutoComplete property, the default value is true, so after the database is connected, it will release itself.
After setting the Autocomlete to False or error, trace the discovery in COM + 's OnActivate event, and when it is activated, the AutoComplete property is automatically set to ture, so it will release itself after the first time it connects to the database.
In COM + 's Ononactivate event, write:
Autocomplete:=false;
The client is connected one at a time and there is no problem accessing the database multiple times.
In this way, COM + is not automatically freed, you need to add a method in COM +, SetComplete in this method, and then call this method to release COM + after the client has run out of COM +.
After the above exploration, the following conclusions: in COM +, if you want to maintain state information, you need to do some work, because COM + default is stateless, every time it is called by the client, it will determine whether it should release itself, if we do not want it to release, it is necessary to manually intervene, Finally we have to release it artificially.