Step 4: Create Executants to Perform the Business Operations

Once a Windows DNA application's business operations and respective request syntaxes have been defined, the next step is to create the executants that will ultimately perform the application's business operations. The DNA PurchaseOrder application relies on the AccountsExec, InventoryExec, LineItemExec, and PurchaseOrderExec executants to perform the business operations defined earlier in Tables 6-9, and relies on the UniqueIDGen and UniqueIDAllocBatch objects to generate the primary key values for each row inserted into the application's underlying database tables. While executants are ultimately responsible for performing business operations, they are free to use whatever means necessary. Some Windows DNA applications issue batches of SQL statements to manipulate and update their underlying data source(s), while others like the DNA PurchaseOrder application rely on the increased performance offered by SQL stored procedures. The SQL stored procedures required to perform the business operations of the DNA PurchaseOrder application are described in the following table.

Table 15. The Stored Procedures Required by the DNA PurchaseOrder Application

Stored procedure Description
sp_AllocBatchOfUniqueIDs Allocates a batch of 100 unique IDs.
sp_decrementBalance_Accounts Decrements the balance of a particular account by a user-defined amount.
sp_decrementQOH_Inventory Decrements the quantities on hand of a particular inventory item by a user-defined amount.
sp_delete_Accounts Deletes an account from the underlying Accounts database table.
sp_delete_Inventory Deletes an inventory item from the underlying Inventory database table.
sp_delete_LineItems Deletes a line item from the underlying LineItems database table.
sp_delete_PurchaseOrders Deletes a purchase order from the underlying PurchaseOrders database table.
sp_deleteByPurchaseOrder_LineItems Deletes all of the line items associated with a particular purchase order from the underlying LineItems database table.
sp_incrementBalance_Accounts Increments the balance of a particular account by a user-defined amount.
sp_incrementQOH_Inventory Increments the quantities on hand of a particular inventory item by a user-defined amount.
sp_insert_Accounts Inserts a new account into the underlying Accounts database table.
sp_insert_Inventory Inserts a new inventory item into the underlying Inventory database table.
sp_insert_LineItems Inserts a new line item into the underlying LineItems database table.
sp_insert_PurchaseOrders Inserts a new purchase order into the underlying PurchaseOrders database table.
sp_update_Accounts Modifies an account that already exists in the underlying Accounts database table.
sp_update_Inventory Modifies an inventory item that already exists in the underlying Inventory database table.
sp_update_LineItems Modifies a line item that already exists in the underlying LineItems database table.
sp_update_PurchaseOrders Modifies a purchase order that already exists in the underlying PurchaseOrders database table.

To create the stored procedures required by the DNA PurchaseOrder application

  1. Start the SQL Server Enterprise Manager if it's not already running.

  2. From the SQL Server Enterprise Manager Tools menu, select SQL Server Query Analyzer.

  3. Select the DNADesign database in the DB drop-down list box.

  4. Execute the SQL scripts in Listings 15-32 sequentially to create the required stored procedures.

If everything is successful, you should be able to select the Databases\DNADesign\Stored Procedures node in the left-hand pane of the SQL Server Enterprise Manager and see the stored procedures listed in Table 15 in the right-hand pane.

Regardless of whether an application issues batches of SQL statements or executes SQL stored procedures, the business operations performed by Windows DNA application executants should be performed inside MTS transactions. MTS transactions allow developers to concentrate on implementing business operations without having to worry about problems caused by partially completed operations, operations leaving the underlying data source in an unexpected state, concurrently executing operations, or results not surviving system failure. Besides providing transactions, MTS also provides resource pooling, process isolation, and role-based security. The DNA PurchaseOrder executants use MTS's role-based security to ensure sensitive business operations are only accessible by authorized personnel.

' Only Administrators can create accounts
If Not GetObjectContext.IsCallerInRole("Administrators") Then GoTo ErrorHandler

To implement the DNA PurchaseOrder executants

  1. Start Visual Basic if it's not already running.

  2. From the File menu, select New Project.

  3. Select ActiveX DLL from the New Project window and click OK.

  4. From the Project menu, select Project1 Properties, type POExecutants in the Project Name text box, and click OK.

  5. From the Project menu, select References, place check marks next to POInterfaces, Microsoft ActiveX Data Access Objects 2.1 Library, and Microsoft Transaction Server Type Library (c:\winnt\system32\mts\mtxas.dll) in the Available References list box, and click OK.

  6. Create three additional class modules (for a total of four) to contain the executant implementations, and name them AccountExec, InventoryExec, LineItemExec, and PurchaseOrderExec.

  7. Implement each executant using the code in Listings 33-36.

  8. Create a new module to contain any global variables and name it Global.

  9. Declare a global constant that defines the DSN connection string using the following code:
    Option Explicit
    
    ' Use the native SQL OLEDB provider
    Public Const gstrCONNECT = "Provider=SQLOLEDB;Database=DNADesign;UID=sa;PWD="
    

Early-binding clients like those developed using Visual Basic, C/C++, and Java will most likely communicate with the executants using the custom interfaces just defined for performance and type safety reasons. However, the executants must also be accessible from late-binding clients, which includes ActiveX Scripting hosts like Microsoft Internet Explorer and Active Server Pages (ASP). Typically, such late-binding clients have a limited range of supported data types, and are only capable of accessing an object's default Automation interface. Because these late-binding clients will not be able to access the executant through the custom interface, the executant must implement a scriptable default interface. The scriptable default interface implemented by the executant should contain the same properties and methods as those defined by the custom interface, albeit with a few minor adjustments to accommodate the way Microsoft Visual Basic® Scripting Edition (VBScript) handles ByRef arguments (See Knowledge Base Article ID: Q172214). Implementing the properties and methods that are copied from the custom interface is usually a simple matter of delegating to the custom interface implementation, although occasionally preliminary data type coercion is required.

Public Function Destroy(ByVal lngAccountID As Long) As Boolean
    ' Delegate the default interface implementation
    ' to the appropriate interface implementation
    Destroy = IAccountExec_Destroy(lngAccountID)
End Function

To implement a scriptable default interface for each executant

Once the scriptable default interface for each executant has been implemented, the UniqueIDAllocBatch and UniqueIDGen objects that are used to generate unique identifiers for use as primary key values for each row in the Accounts, Inventory, LineItems, and PurchaseOrders tables must be created.

To create the UniqueIDAllocBatch and UniqueIDGen objects

  1. From the Project menu, select References, place a check mark next to MTS Shared Property Manager Library (c:\winnt\system32\mts\mtxspm.dll) in the Available References list box, and click OK.

  2. Create one additional class module (for a total of two) and name them UniqueIDAllocBatch and UniqueIDGen.

  3. Implement UniqueIDAllocBatch and UniqueIDGen using the code in Listings 41 and 42.

Before the DNA PurchaseOrder executants can be compiled, each executant must declare the type of transactional support it requires from MTS. The types of transactional support offered by MTS are described in the following table.

Table 16. Transactional Support Offered by MTS

Transactional support Description
Requires a transaction Objects must execute within the scope of a transaction. When a new object is created, it inherits the transaction from the client. If the client does not have a transaction, MTS automatically creates a new transaction for the object.
Requires a new transaction Objects must execute within their own transactions. When a new object is created, MTS automatically creates a new transaction for the object, regardless of whether its client has a transaction.
Supports transactions Objects can execute within the scope of their client's transactions. When a new object is created, it inherits the transaction from the client, if the client has a transaction; otherwise the new object is created without a transaction.
Does not support transactions Objects do not run within the scope of transactions. When a new object is created, it is created without a transaction, regardless of whether its client has a transaction.

For the DNA PurchaseOrder application, the AccountExec, InventoryExec, LineItemExec, PurchaseOrderExec, and UniqueIDGen objects all "Require a Transaction," while the UniqueIDAllocBatch object "Requires a New Transaction."

To declare the transactional support required by the DNA PurchaseOrder executants

  1. Open the AccountExec, InventoryExec, LineItemExec, PurchaseOrderExec, and UniqueIDGen class modules and use the Properties window to set their MTSTransaction mode property to 2-RequiresTransaction.

  2. Open the UniqueIDAllocBatch class module and use the Properties window to set its MTSTransaction mode property to 4-RequiresNewTransaction.

Once each executant has been completely implemented, save your work, and compile the ActiveX DLL into POExecutants.dll.