How to maintain COM status information in Delphi
Cipherliu
The problem is to start: I need to write a COM to connect different databases. Some friends may say that a COM should be created for each database, but in my system. We are doing an education aid system, users are schools (of course, including teachers, students, parents) in schools, we build a database for each school, and the structure of these databases is the same. Of course, we have managed databases to coordinate the relationship between each database. Each time to add a school user, we activate a new database to the customer, that is, the number of our database is increasing, and our client has only one, we will not develop different for each school. The client, our COM is also only one, not for each database. So I have to let it connect to different databases according to the user's identity in COM .
Obviously, this COM should provide a method to allow its caller (which can be a client application, or other middleware) to select the connected database, in actual we are in the management library of the user Go to its database name, then connect the user database, here, in order to simplify the problem, we believe that the caller already knows the name of the database, and directly calls this database.
Add a private member DBName: String to save the database name to be connected to save the COM class. You should also provide such a method to set its value, I started writing like this.
Procedure TMTSDBCONN.CONNECTTTO (SDBNAME: STRING);
Begin
Try
DBNAME: = SDBNAME;
Setcomplete;
Except
Setabort;
END;
END;
Then put it in the Adoconnection, Adodataset, and DataSetProvider controls, named Adoc, Adods, DSP, respectively. Set the connection between them, set the connection character of the Adoc to connect to the database "DB1", which is the default value, then in the Adoc's BeforeConnect event:
Adoc.connectionstring: = ConnectStringa 'Initial Catalog =' DBNAME ';' ConnectStringc;
The connectionstringa and connectstringc here are dynamically build a connection string, and the pre-set string is set, 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, install this COM . Then write a client program to call it. Place a DCOMCONNECTION in the client program, connect to the COM server above, then put a clientDataSet, set its RemoteServer and the Provider property, and then write the SQL statement in its CommandText. Then, put the DataSource control and DBGRID control, build the connection between them. Finally put a button, in its Click event:
DCOMCONNECTION1.CONNECTED: = TRUE;
DCOMCONNECT1.APPServer.Connect ('db2');
ClientDataSet1.Active: = TRUE;
DCOMCONNECTION1.CONNECTED: = FALSE;
This code is to test it, you can access the DB2 database data. However, the result is that when the button is bit, it is always an error. What is the reason?
Back to COM project, debug it, set breakpoints in Connectto and AdocbeforeConnect, and discover the program to execute
DBNAME: = SDBNAME;
When you have already set the value of DBNAME to "DB2", it is executed
Adoc.connectionstring: = ConnectStringa 'Initial Catalog =' DBNAME ';' ConnectStringc;
When DBNAME became an empty string, it was wrong.
Why do DBNAMEs lose? It turned out to be because in Connectto, the setcomplete method was called, the setcomplete method thought that this COM has completed the task, release this COM object, and then connects the database, and creates a new COM , which is of course null. .
After finding the reason, change the setcomplete into enableCommit; compile, run the client, and finally run successfully, retrieve the data in the DB2 database.
However, in the client program, put it in another clientDataSet, after opening the clientDataSet1, open the clientDataSet2, and want to continue to access the data in DB2, and report an error. Change the program to
DCOMCONNECT1.APPServer.Connect ('db2');
ClientDataSet1.Active: = TRUE;
ClientDataSet1.Active: = false;
ClientDataSet1.Active: = TRUE;
Even if only one clientDataSet is used, it will still be wrong when it is turned off.
But if the client is written
DCOMCONNECT1.APPServer.Connect ('db2');
ClientDataSet1.Active: = TRUE;
DCOMCONNECT1.APPServer.Connect ('db2');
ClientDataSet 2.Active: = true;
It can be successful. But this seems to be very unrest, why does COM release yourself after connecting the database?
It turns out that TMTSDataModule has an AutoComplete property, the default value is true, so after the database is connected, it will still release himself. After setting AutoComlete to false, it is wrong, track discovery in COM onactivate events, when it is activated, the AutoComplete property is automatically set to TURE, so it will release yourself after it is connected to the database for the first time.
In Com 's ononActivate event, write:
AutoComplete: = FALSE;
The client is connected once, and there is no problem with multiple access to the database.
But in this way, COM will not be released automatically, you need to add a method in COM , setComplete in this method, and then call this method to release this method after COM after COM .
After the above exploration, you can draw the following conclusions: In Com , if you want to keep status information, you need to do some work, because COM defaults are stateless, each time it is called by the client, is it to release yourself If we don't want it to release, we must intervene, and finally we must manually release it.