MC Press Online

Wednesday, Feb 22nd

Last updateSun, 19 Feb 2017 12pm

You are here: Home ARTICLES Analytics & Cognitive DB2 .NET Integration with DB2 UDB for iSeries

Database / DB2

.NET Integration with DB2 UDB for iSeries

Support MC Press - Visit Our Sponsors

NEW BOOK!

Evolve Your RPG Coding: Move from OPM to ILE ... and Beyond


ORDER YOUR COPY

*******************

Click for this Month's

Bookstore Special Deals

Microsoft's .NET Framework is gaining acceptance among solution developers who traditionally rely on Microsoft development tools. Some of these developers want to take advantage of the robust transaction support, tight security, reliable messaging, and workload and system management that are unique strengths of iSeries servers. It seems that the combination of .NET Framework and a powerful database server, such as DB2 UDB for iSeries, can result in a scalable software solution that's very appealing to the development community.

Typically, .NET applications use ADO.NET classes to access and manipulate data stored in databases. ADO.NET is an evolutionary improvement to the Microsoft ActiveX Data Objects (ADO) programming interface. This article discusses how to efficiently implement the ADO.NET programming model to access the iSeries database. I'll also illustrate using DB2 add-ins for Visual Studio .NET to significantly speed up the development process.

The .NET applications rely on services of .NET providers for communication with back-end database servers. A .NET data provider is used for connecting to a database, executing commands, and retrieving results. Currently, four providers can be used to access DB2 UDB from .NET applications:

  • V5R3 iSeries Access .NET provider implemented by IBM Rochester
  • The DB2 for Linux, UNIX, and Windows (LUW) V8.2 (formerly Stinger) .NET provider implemented by IBM software group
  • ODBC .NET Data Provider, the Microsoft-supplied ODBC bridge provider using the iSeries Access for Windows ODBC driver for underlying database connectivity
  • OLE DB .NET Data Provider, the Microsoft-supplied OLE DB bridge provider using the iSeries Access OLE DB driver for underlying database connectivity

The OLE DB .NET provider and the ODBC .NET provider are called "unmanaged" providers, meaning that the code has been compiled directly into a binary executable, so it runs outside of the .NET framework. The unmanaged providers usually deliver suboptimal performance because they involve jumping in and out of the .NET Framework environment for every interface call. On the other hand, the iSeries Access .NET provider and the DB2 .NET provider are called "managed" providers. Managed providers are compiled into .NET assemblies that can be executed in the context of the .NET Framework. In this case, the application/provider interaction does not require API calls that cross the .NET Framework boundary.

The iSeries Access .NET Provider

The iSeries Access .NET provider is sometimes called "native iSeries .NET provider." It uses a highly optimized, proprietary protocol to communicate with the iSeries database server job. The database server jobs are called QZDASOINIT, and they typically run in the QUSRWRK subsystem. A database server job runs the SQL requests on behalf of the .NET provider. More precisely, when a .NET application submits an SQL statement, the provider passes the statement to a server job that, in turn, calls the DB2 runtime to execute the statement. The results are then reformatted and returned to the caller.

The provider supports a full set of .NET data types and provides rich SQL functionality to enable applications to easily access and process data stored on your iSeries. These features are currently implemented in the iSeries Access .NET provider:

  • SQL (INSERT, UPDATE, DELETE, SELECT)
  • Commitment control
  • Connection pooling
  • SQL naming
  • Unicode
  • Threads
  • IASPs (multiple databases)
  • Stored procedure support

Two additional features have been recently shipped in the iSeries Access SI15176 Service Pack:

  • System naming ( / )
  • Large Objects (LOBs)

The following functionality is not yet available through the provider:

  • SQL package support (extended dynamic SQL)
  • Data links
  • User-defined types
  • Record-level access
  • CMD/PGM call
  • Data queues

Prerequisites

The iSeries Access .NET provider ships with iSeries Access V5R3. It supports the iSeries servers running i5/OS V5R3 and OS/400 V5R2. Note that some functionality, such as 63-digit decimal precision, is available only on V5R3 servers. For the best code stability, you should always load the latest database group PTF on the iSeries system (SF99503 for V5R3 or SF99502 for V5R2) as well as the most recent V5R3 iSeries Access Service Pack. As with any other managed provider, the .NET Framework needs to be already installed on your PC.

Sample Application

This section covers implementation details for a sample Visual Basic (VB) .NET application called DB2i5Access (download here). The program uses the iSeries Access .NET provider to obtain a database connection and to manipulate database rows in a DB2 table called STAFF. The table is part of the sample DB2 schema, and it can be created with this stored procedure call:

CALL QSYS.CREATE_SQL_SAMPLE('DB2USER');

The procedure has been shipped with i5/OS and OS/400 since V5R1.

The application works in the disconnected mode. In the disconnected mode, a DataAdapter object retrieves data from the database and stores it in a DataSet object that serves as a local data cache. A .NET application can use the data cached in a DataSet without requiring multiple trips to the database. A DataAdapter can also implicitly update the central database with changes made to the DataSet. We used Microsoft Visual Studio .NET 2003 to develop the sample application. The main application dialog is shown in Figure 1.

http://www.mcpressonline.com/articles/images/2002/dotNET%20Integration%20with%20DB2%20for%20iSeriesV400.png

Figure 1: Here's your sample DB2i5Access application.

Overview

After a new project is created, a reference to the assembly that contains the iSeries Access .NET provider needs to be added to the solution. You can accomplish this task by right-clicking the References icon in Solutions Explorer and selecting Add Reference. In the Add Reference dialog, find the IBM DB2 for iSeries .NET provider component and click Select and then OK. It is also very useful to add the iSeries Access provider classes to the Visual Studio Toolbox. To do so, select Tools > Add/Remove Toolbox items, and on the Customize Toolbox dialog, check the iSeries provider-specific classes (iDB2Command, iDB2CommandBuilder, iDB2Connection, and iDB2DataAdapter). Now, drag and drop the iSeries provider classes onto the design pane. Currently, the iSeries .NET provider does not provide wizards to allow you to visually configure the classes required to access and modify DB2 data, so most of the tasks need to be accomplished programmatically. As mentioned, in the disconnected mode, there are several ADO.NET objects that cooperate to provide the database access mechanism. The required objects and their relationships are illustrated in Figure 2.

http://www.mcpressonline.com/articles/images/2002/dotNET%20Integration%20with%20DB2%20for%20iSeriesV401.png

Figure 2: In the disconnected mode, ADO.NET objects provide the database access mechanism.

Let's have a closer look at the most critical source code fragments that need to be manually implemented by a database developer.

iDB2Connection

An ADO.NET connection object establishes a connection to a specific data source. For instance, the iDB2Connection object connects to DB2 UDB for iSeries. To successfully open an iSeries connection, security information such as user ID and password must be passed to the database. Typically, a ConnectionString property provides this information. The following code shows how to use the iDB2Connection object:

Me.conMyiSeries = New iDB2Connection
Me.conMyiSeries.ConnectionString = "DataSource=PWD1;Connection 

Timeout=30;UserID=db2user;Password=db2pwd"

Note the syntax of the keywords on the connection string. The keywords are provider-specific and usually differ for different databases. In addition to the authentication info, the iSeries connection string may also specify other connection parameters, such as Default Collection (schema), Default Isolation Level, Pooling, etc. Consult the DB2 UDB for iSeries .NET provider Technical Reference for a complete list of supported parameters. The above code sample, for illustration purposes, has the user ID and password hard-coded in the application program. In fact, our sample application uses TextBox controls to allow the user to specify valid credentials at runtime.

iDB2Command

An iDB2Command object executes action statements and submits queries. It has several properties that specify the execution context:

  • Connection--A reference to a connection object used for communication with the database
  • CommandType--Set to one of the following values: Text, StoredProcedure, TableDirect
  • CommandText--Contains the text of an SQL statement or the name of the stored procedure to be executed
  • Parameters--Values required by parameterized SQL statement or stored procedure

In our scenario, we instantiate four iDB2Command objects that the iDB2DataAdapter needs. They represent the four fundamental SQL statements: SELECT, INSERT, UPDATE, and DELETE. The following code illustrates how to create and set up iDB2Command objects:

Me.cmdSelect = New iDB2Command
Me.cmdUpdate = New iDB2Command
Me.cmdDelete = New iDB2Command
Me.cmdInsert = New iDB2Command 
'cmdSelect
Me.cmdSelect.CommandText = "SELECT * FROM STAFF" [1]
Me.cmdSelect.Connection = Me.conMyiSeries
'cmdDelete
Me.cmdDelete.CommandText = "DELETE FROM DB2USER.STAFF WHERE ID = ?" [2]
Me.cmdDelete.Connection = Me.conMyiSeries

Me.cmdDelete.Parameters.Add(New iDB2Parameter("ID", _
iDB2DbType.iDB2SmallInt, 5, System.Data.ParameterDirection.Input, _
False, CType(0, Byte), CType(0, Byte), "ID", _

System.Data.DataRowVersion.Original, Nothing))


For clarity, UPDATE and INSERT statements are not listed here. At [1], the SELECT command is set up to retrieve all rows from the STAFF table over the conMyiSeries connection. At [2], a parameterized DELETE statement is specified. The statement uses a parameter marker (?) as a placeholder for the ID value that will be provided at runtime. The parameter markers foster a more efficient processing of SQL statements because a parameterized statement can be prepared once and executed many times. The DELETE statement requires an iDB2Parameter object that is bound to the parameter marker. Note that the original value of the ID column is used to locate the staff member row in DB2. The statement unconditionally deletes the corresponding row in the database. In other words, it does not take into account whether the original row image has been modified by other users. This is probably not the best business practice. In a more realistic scenario, we would probably use the so-called "optimistic locking approach," where we would check if the local image still matched the image on the database server before deleting a row. This could be accomplished with a DELETE statement modified as shown below:

DELETE FROM DB2USER.STAFF WHERE ( (ID = ?)
AND ((CAST( ? AS VARCHAR(9)) IS NULL AND CAST(NAME AS VARCHAR(9)) IS NULL)
OR (CAST(NAME AS VARCHAR(9)) = ?))
AND ((CAST( ? AS SMALLINT) IS NULL AND CAST(DEPT AS SMALLINT) IS NULL)
OR (CAST(DEPT AS SMALLINT) = ?))
AND ((CAST( ? AS CHAR(5)) IS NULL AND CAST(JOB AS CHAR(5)) IS NULL)
OR (CAST(JOB AS CHAR(5)) = ?)) AND ((CAST( ? AS SMALLINT) IS NULL
AND CAST(YEARS AS SMALLINT) IS NULL) OR (CAST(YEARS AS SMALLINT) = ?))
AND ((CAST( ? AS DEC(7,2)) IS NULL AND CAST(SALARY AS DEC(7,2)) IS NULL)
OR (CAST(SALARY AS DEC(7,2)) = ?))
AND ((CAST( ? AS DEC(7,2)) IS NULL AND CAST(COMM AS DEC(7,2)) IS NULL)
OR (CAST(COMM AS DEC(7,2)) = ?)) )

The same approach could also be applied to the UPDATE statement.

iDB2DataAdapter

An iDB2DataAdapter is a bridge that links an iSeries database and a local data cache represented by a DataSet object. The iDB2DataAdapter encapsulates a database connection and a set of SQL commands that are used to retrieve the data from the database and update the database with the changes made to the DataSet. Once the connection and the command's objects have been defined, the iDB2DataAdapter configuration is pretty straightforward. See the following code:

Me.daStaff.DeleteCommand = Me.cmdDelete
Me.daStaff.InsertCommand = Me.cmdInsert
Me.daStaff.SelectCommand = Me.cmdSelect
Me.daStaff.UpdateCommand = Me.cmdUpdate

Error Handling

Exception handling in ADO.NET complies with the Common Language Runtime (CLR) specification and is consistent across all supported .NET programming languages. In CLR, the control structure is the Try-Catch-Finally statement. An error that occurs in the Try block is handled in the Catch block. The iSeries Access .NET provider implements the iDB2Exception object that can be used to monitor for the provider-specific exceptions. The provider throws an iDB2Exception whenever it encounters an error generated from the iSeries host server or from the underlying iSeries Access APIs .

The iDB2Exception contains a collection of one or more iDB2Error objects. The DB2i5Access application uses the iDB2Exception to intercept database errors that can occur at the time the rows are loaded into the DataSet or the updates are submitted to the database. For example, the btnLoad_Click method monitors for iSeries-specific errors and shows an appropriate error message box when unexpected conditions are encountered. See the following code fragment for implementation details:

Private Sub btnLoad_Click(ByVal sender As System.Object, ByVal e As 

System.EventArgs) Handles btnLoad.Click
        Try
            dsStaff.Clear()
            daStaff.Fill(dsStaff.STAFF)
        Catch Xcp As iDB2Exception
            Dim sqle As iDB2Error
            For Each sqle In Xcp.Errors
      MessageBox.Show(Xcp.ToString(), "DB2 Server Error", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
            Next
        End Try
End Sub

Troubleshooting

Troubleshooting a multi-tier application is usually not trivial because the developer needs to deal with software components that reside in different operating system environments. Two tools can be particularly useful for problem resolution:

  • The job log messages for a database server job usually provide enough details to isolate DB2 UDB for iSeries runtime issues.
  • The iSeries Access .NET provider trace utility provides granular information about the data flow between the .NET application and the iSeries server job.

Job Log

The iSeries Access .NET provider communicates with a corresponding iSeries server job. This server job runs the SQL requests on behalf of the .NET client. The iSeries database server jobs are called QZDASOINIT, and they run in the QUSRWRK subsystem. At any given time, many database server jobs may be active on the system, so the first step is to identify the job that serves the particular client connection, which is easily done by running the following CL command:

WRKOBJLCK OBJ(DB2USER) OBJTYPE(*USRPRF)

Here, DB2USER is the user profile that is used to connect to the iSeries server. This approach works even in the disconnected mode. Thanks to connection pooling, a corresponding job is held even after the iDB2DataAdapter has closed the database connection.

Sometimes, it is also useful to include debug messages in the job log. The debug messages are informational messages written to the job log about the implementation of a query. They describe query implementation methods, such as use of indexes, join order, open data path (ODP) implementation (reusable versus non-reusable), and so on. The easiest way to instruct the iSeries to include the debug messages is to set the Trace property on the connection string of the iDB2Connection object:

Me.conMyiSeries.ConnectionString = 

"DataSource=TPLX;UserID=db2user;Password=db2pwd;Trace=StartDebug"

A sample of the job log messages with debug messages enabled is shown below:

**** Starting optimizer debug message for query .
Unable to retrieve query options file.
All access paths were considered for file STAFF.
Arrival sequence access was used for file STAFF.
**** Ending debug message for query .
ODP created.
Blocking used for query.
Cursor C000001 opened.
DESCRIBE of prepared statement S000001 completed.
35 rows fetched from cursor C000001.
Cursor C000001 was closed.

Provider Trace Utility

The iSeries Access .NET provider ships with a tracing utility, which can be used to collect detailed client-side traces. The .NET provider tracing is turned off by default. It can be enabled by calling the CWBMPTRC program on Windows. Here's an example of how to switch on tracing:

cwbmptrc +t

The trace file by default is named IDB2TRACE.TXT and is stored in the C:Documents and SettingsAll UsersDocumentsIBMClient Access directory.

DB2 UDB V8.2 .NET Provider

The recently announced IBM DB2 UDB for Linux, UNIX, Windows (LUW) V8.2 (formerly "Stinger") provides a high level of integration with Visual Studio .NET, improved performance for .NET applications, and significant enhancements for stored procedure and user-defined function developers. This new version also introduced .NET connectivity and simplified programming facilities for building applications that work with DB2 UDB for iSeries servers. The iSeries support relies on services provided by DB2 Connect. DB2 Connect is offered as separate Windows licensed products:

  • Enterprise Edition
  • Personal Edition
  • DB2 Connect Unlimited Edition
  • Application Server Edition

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for Windows.

DB2 Connect implements the Distributed Relational Database Architecture (DRDA) to access data stored in DB2 UDB for iSeries and other DRDA-compliant database servers. A .NET client that uses DB2 .NET provider connects to a DRDA server job on iSeries. The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem. You can use the DB2 Configuration Assistant (db2ca) on the Windows client to configure the required DRDA connection to the iSeries.

Once the connection has been configured, you can take advantage of the DB2 Visual Studio add-in. The DB2 add-in provides a rich collection of functions that support DB2 servers directly in Visual Studio's IDE. These are the most important features:

  • DB2 .NET Managed Provider
  • Solution Explorer--create and manage DB2 projects
  • IBM Explorer--view DB2 server catalog information and client side ADO.NET code generation
  • SQL Editor--edit DB2 scripts (includes syntax colorization and statement auto-completion)
  • DB2 Tools Toolbar

In addition, the DB2 add-in provides wizards to visually configure DB2 commands, adapters, etc. For example, the DB2 Data Adapter Configuration wizard allows you to define SQL statements and stored procedure calls. It also allows you to define the structure of the result set and map SQL command parameters to columns in the result set.

To illustrate how a wizard simplifies the developer's work, assume that we decided to use the DB2DataAdapter in our DB2i5Access sample application. In this case, instead of programmatically defining the database connection, required SQL statements, and statements parameters, we drag a DB2DataAdapter object from the Visual Studio Toolbox and drop it on the form designer. This launches the configuration wizard. First, we provide the iSeries database connection information. Remember, the DRDA connection to the iSeries needs to exist at this time (use db2ca to configure it). Then, we specify what SQL commands are required by the adapter. In addition to the default SELECT, we choose INSERT, UPDATE, and DELETE. Next, we specify the SELECT statement as shown in Figure 3.

http://www.mcpressonline.com/articles/images/2002/dotNET%20Integration%20with%20DB2%20for%20iSeriesV402.png

Figure 3: Define SQL statements with the DB2 Data Adapter Configuration Wizard.
At this point, the wizard also allows you to validate the statement on the back-end iSeries database as well as provide the table to dataset mapping. Similarly, we define other SQL statements. We use the wizard's Generate function to automatically generate the statement text along with all required parameters. For example, the Generate function used on the UPDATE statement dialog generates the UPDATE statement that implements the optimistic locking. This is shown in Figure 4.

http://www.mcpressonline.com/articles/images/2002/dotNET%20Integration%20with%20DB2%20for%20iSeriesV403.png

Figure 4: Generate an Update statement.
At the end of the configuration process, the wizard creates two objects associated with the VB Form class: db2Connection1 and DB2DataAdapter1. The wizard also generates the necessary code in the "Windows Form Designer generated code" region. The developer should not modify this code. The wizard should be used to make any changes in the DB2DataAdapter configuration.

Hopefully, this short walkthrough has given you a taste of the truly unique capabilities of the DB2 add-in. See DB2 Development Add-In Technical Preview for more information.

What Provider Is Right for You?

Choosing the appropriate .NET data provider for your application depends on your environment. If you plan to access only the iSeries database, the DB2 UDB for iSeries .NET provider should be your choice. This managed provider will provide better performance than using the System.Data.OleDb provider to bridge to the iSeries Access OLE DB provider or using the Microsoft.Data.Odbc provider to bridge to the iSeries Access ODBC driver.

Consider the DB2 UDB (LUW) provider if you need to access different DB2 UDB platforms, such as DB2 UDB for Windows or DB2 UDB for z/OS, in addition to iSeries or if you wish to take advantage of the GUI add-Ins discussed in the previous section.

Jarek Miszczyk is the Senior Software Engineer, PartnerWorld for Developers, IBM Rochester. He can be reached by email at This email address is being protected from spambots. You need JavaScript enabled to view it..

BLOG COMMENTS POWERED BY DISQUS