How ADO Further Simplifies Interprocess Communication

[Previous] [Next]

ADO Recordset objects are more flexible than most COM objects. When you pass a Recordset object variable to a procedure, two results are possible: the procedure will receive a reference (or pointer) to the same Recordset object (as with most COM objects), or the procedure will receive a separate Recordset object that contains the same data. The result of passing a Recordset object variable from one procedure to another depends on many factors, such as whether the procedure call crosses a process boundary, whether the Recordset contents are stored in the ADO Cursor Engine, whether the procedure you're calling can accept the Recordset object variable by reference or by value, and so on. Let's take a closer look at some of these factors and the behaviors associated with them.

Passing Recordsets Within a Process

When you pass a Recordset object variable between procedures within the same process, ADO passes a reference to the object. This means that you'll have multiple references to the same Recordset object. The changes you make to the Recordset in the called function—such as modifying records and navigating—will affect all references to the Recordset.

You cannot pass a Recordset object variable by value within a single process and get a separate copy of your data. However, you can use the Recordset object's Clone method to get separate bookmarks. (See the discussion of the Clone method in Chapter 4.) Another option is to persist the Recordset (as discussed in Chapter 13) to a file or a stream and then reopen it.

Passing Recordsets Across Process Boundaries

Of course, I wouldn't have mentioned custom marshaling routines if ADO didn't utilize this feature of COM. The way in which ADO marshals Recordset objects across process boundaries is based on whether you use the ADO Cursor Engine to store the results of your query.

Server-side Recordsets

With a server-side cursor, the database and/or the OLE DB provider manage the results of the query. In order to access that particular cursor, you need to maintain a single physical connection to the database. For this reason, ADO passes a pointer to the Recordset object across the process boundary. Therefore, whether you pass by value or by reference, server-side Recordsets are always passed by reference.

Let's talk about the repercussions of passing Recordset object variables in this fashion. Imagine building a business object in a Microsoft ActiveX EXE and using that EXE as a middle-tier server that communicates with your database. (Although an ActiveX DLL running in Component Services, Microsoft Transaction Server, or Internet Information Services would be a more scalable approach, the ActiveX EXE offers a simpler illustration of this point.)

In this scenario, your client application is installed on multiple machines, and each client communicates with the business object on a separate machine using DCOM, which then communicates with your database. To retrieve data, the client calls a function within your business object that submits a query to the database, stores the results in a server-side cursor, and passes the Recordset object variable to the client.

The client application doesn't receive the data inside the Recordset object; it receives only a reference to the Recordset, which continues to reside on the server machine, as shown in Figure 15-1. As a result, each time your client accesses the Recordset object to examine its contents, it makes network calls to communicate with the business object running on the server.

click to view at full size.

Figure 15-1 A client communicating across a process boundary with a server-side Recordset.

This application architecture works quite well for a small number of users, but it scales poorly. The business object in this architecture is considered "stateful," meaning it must maintain data on behalf of the client. Because it contains client-specific data, a separate instance of the business object must exist for each instance of a running client. Business objects that are "stateless" retain no data for the client, so the server can use one object to communicate with multiple clients. The result is that stateless objects scale well.

A middle-tier server that serves up stateful business objects must store data for each client. The more data each business object needs to maintain, the more memory that server uses for each client accessing it. The more memory each client requires on the server, the fewer clients that server can support. Because of the constant network traffic required and the limited scalability of this architecture, it's not suitable for applications that accommodate more than a handful of users.

NOTE
If you're going to employ such an architecture, I recommend using your own ActiveX EXE as the server rather than Component Services or Internet Information Services. Those high-powered servers are most helpful if you're using stateless objects. Also, by using your own ActiveX EXE as the server, you have a little more control over how your server manages its state.

Client-side Recordsets

When you pass a client-side Recordset object variable across process boundaries, the ADO libraries are loaded in the client and server processes. Suppose that you have a business object running on a separate server. Your client calls a function on the business object that returns a Recordset object. The ADO libraries on the server marshal the Recordset data from the ADO Cursor Engine running on the server to the ADO libraries on the client. The ADO libraries on the client machine unmarshal the data in the client's Cursor Engine and create a new local Recordset object to access that data.

Once the call to the function on your business object completes, your client application will have its own local Recordset object, rather than a pointer to a Recordset object that's actually maintained by your business object. The business object can now close or release its Recordset object without affecting the client application's Recordset object.

The result of this process is that your client receives Recordsets served up by your business objects but stores all the Recordset data locally. The business object is now stateless. Your client will not incur network round-trips when you access the data in your Recordset, and you can take advantage of the ADO Cursor Engine's batch updating features. Because your data is in a Recordset object rather than in your own data structures, you can use bound controls to interact with your data.

Passing client-side Recordsets by reference and by value

Unlike server-side Recordsets, when you pass client-side Recordsets across process boundaries, the resulting objects will behave differently depending on whether you pass the object variable by reference or by value.

Earlier we talked about how COM passes standard data types, such as integers and strings, across process boundaries. If you pass an integer by value, COM passes the value of the integer across the process boundary into an integer variable in the process of the procedure that you're calling. If you pass an integer by reference, COM follows those same steps but, at the end of the procedure call, passes that value back into the integer variable in the calling process.

You'll see similar behavior when you pass your client-side Recordset across process boundaries. Let's say that your client application has a Recordset object that was returned by a business object running on a separate machine in your network. Because you used the ADO Cursor Engine to handle the results of the query and specified adLockBatchOptimistic as the LockType when you opened your Recordset, the client application stores all the data locally. You built your client application so that the user can modify the data in the Recordset. Now you want to pass those changes to the database.

So you build a function on your business object that takes a Recordset object as a parameter. This function opens a connection to your database, associates that connection with the Recordset object, and then submits the pending changes in the Recordset by calling the Recordset's UpdateBatch method. Calling UpdateBatch changes the data in the Recordset slightly—the successful updates are no longer marked as pending records.

If you build the function so that the Recordset object variable is passed by value, you'll see the behavior described earlier: ADO passes data into the function so that the function receives its own copy of the Recordset object. Similar to when you pass an integer by value, the changes made to the Recordset object in the function will not affect the Recordset object in the client application.

If you build the function so that the Recordset object variable is passed by reference, the changes made to the Recordset object in the function will also affect the Recordset object in the client application. When the function call completes, the ADO libraries pass the modified Recordset data in the business object to the client application. Thus, when you pass your client-side Recordset object variable by reference across process boundaries, ADO marshals the data in the Recordset object to the function and back again. Microsoft Visual Basic programmers should keep in mind that parameters are, by default, passed by reference.



Programming ADO
Programming MicrosoftВ® ADO.NET 2.0 Core Reference
ISBN: B002ECEFQM
EAN: N/A
Year: 2000
Pages: 131
Authors: David Sceppa

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net