This article is the third and final part of a series that covers some lessons learned when trying to plug Visual Studio into our IBM U2 UniVerse database using IBM’s ADO.NET driver. Part 1 was an overview of how well the ADO.NET driver has worked for us, and the prerequisite software that is required to use it. Part 2 gave some tips on preparing your UniVerse dictionaries for use with Visual Studio. In this part of the series, we finally get to fire up Visual Studio and connect it to the database.
One of the great things about the ADO.NET driver, when compared to other UniVerse APIs like UniOLEDB and UniVerse Objects.NET, is that it allows Visual Studio to finally recognize UniVerse as a database. That means you don’t have to write a bunch of code in order to see the data — you can use use Visual Studio to explore the database and test your SQL statements. (On the other hand, if you prefer to just write code and avoid all the point-and-click stuff, you can skip ahead to this point in the article.)
The first step is to configure your UniVerse database in Visual Studio’s Server Explorer. This process is explained well in IBM’s developerWorks article "Access IBM U2 data server from your .NET applications, Part 2". Since I would strongly advise you to read IBM’s three-part tutorial series anyway, I won’t repeat the information here.You should now have a new node in the Data Connections section of the Server Explorer, as shown in the screenshot on the right, with a name like "<user-ID>@<account>[UNIVERSE 10.02.0000]". Expand that node, and you’ll see 4 sections: Tables, Views (which will be forever empty), Procedures and Functions (also empty). Expand the Tables node and, hopefully, you’ll see a list of the tables in your account. Expand one of the tables, and you’ll hopefully see the columns in that table. Right-click on the table and select "Show Data", and you’ll see a grid containing all the rows of the table. Groovy! UniVerse and Visual Studio sitting in a tree-ee…
Alas, you might, like I, find that Visual Studio’s love for UniVerse is not so easily requited. When I expand the Tables node in our development account, I see the warning on the left. After clicking on the Yes button, I am then left staring at the hourglass for a few minutes before the table list appears. If I expand one of the tables to view its columns, I once again find myself contemplating the Windows hourglass for a minute or so, even if the table only contains a few columns. If I want to use Visual Studio’s query builder with my UniVerse database: you guessed it, again with the hourglass. Trust me, that gets real old real fast!It would seem that Visual Studio’s Explorers like to, well, explore. If you have a large UniVerse master dictionary, all that exploring takes some time. The key to speeding up Visual Studio is to limit how much of your master dictionary it sees. If you read Chapter 4 of the UniVerse ODBC Guide, you’ll find that happily there is a mechanism for doing just that: create a file named HS_FILE_ACCESS and add an entry in it for each file that you want to use with Visual Studio. Unhappily, while this limits the number of tables that you’ll see in Visual Studio, it only makes things slightly faster.
I suspect that the solution to this problem is to create a new account whose master dictionary contains only the data files you want Visual Studio to work with. I’ll be trying this for myself at some point in the future, and I’ll blog about it then.
Fortunately, even if you find that slow performance makes some of Visual Studio’s point-and-click features unusable, you are still left with enough tools to get the job done.
Let’s start with some SELECT queries. Right-click the database connection in the Server Explorer and, instead of New Query, choose New Script. This opens the Script Builder (shown in the screenshot below), an IBM tool that is basically a stripped-down version of Visual Studio’s Query Builder: no Diagram pane, no Criteria pane, just a box for your SQL and a grid with your results. (And a tiny little 1-icon toolbar – cute!). More typing, but a lot less waiting, since this dialog do a scan of your UniVerse master dictionary.

The SELECT commands that you enter here follow most of the same rules as for a SQL database, but there are a few tricky things:
1) Case matters – if your columns are defined in your DICT in upper-case, you must use upper-case here, something that is sure to trip up any SQL Server or Oracle developer.
2) Columns and tables that contain hyphens must be surrounded with double quotes — the square brackets that you may be used to using with other databases won’t cut it here. For example,
select USER.ID from "CSUSER-FILE"
is valid, but not
select USER.ID from [CSUSER-FILE]
or
select user.id from "csuser-file"
Oddly, names that contain a period do not have to be quoted – unlike its SQL database brethren, UniVerse is smart enough to figure out when the period delimits the table ID from the column name.
3) A "SELECT *" query will return the key fields along with whatever fields are defined in a special dictionary entry named "@". For example, if you want SELECT * FROM USERS to return the FIRST-NAME and LAST-NAME fields, you’ll need to edit the dictionary as follows:
ED DICT USERS Record name = @ 2 lines long. ----: 2 0002: 1 2 Bottom at line 2. ----: R FIRST-NAME LAST-NAME 0002: FIRST-NAME LAST-NAME Bottom at line 2. ----: FI "@" filed in file "DICT USER".
If you don’t have a record named "@" in your file’s dictionary, then "SELECT *" will return the column named "@ID" if you have one (which you probably do, since the primary key is automatically added to all dictionaries under this name when you first create them). If you happen to have deleted the "@ID" column, then SELECT * will fail with a "No column rows" error.
What if you have a 200 column table and you want SELECT * to return all 200 columns? Sorry, but you’ll have to enter all 200 column names in that "@" record. And if you add, delete or rename a column, you’ll have to remember to edit that "@" record. I feel your pain! This cumbersome approach dates back to UniVerse’s ODBC driver, and I suppose they can’t change it now without breaking a lot of applications. You can find the details described in inscrutable IBM-ese in the UniVerse ODBC Guide.
4) Errors encountered when executing your SQL statement are reported in a pretty obscure manner. You’ll see a message box with the "Error in SQL. Check the SQL and try again. For error detail information refer to the IBM Output Message Pane". It took me awhile to figure out where the "IBM Output Message Pane" was hidden. It’s in the Output window (Ctrl-W O), but you’ll need to change the "Show output from" combo to "IBM Output Message Pane" as shown below. 
5) If you have subvalued fields, only the first subvalue in the field will appear in the Results grid. (Subvalues are ASCII 252 delimiters which are used to fit multiple fields into the same column). This is presumably a side effect of a bug in IBM’s ADO.NET driver which replaces subvalue delimiters with CR/LF.
6) There are a couple of bugs in the ADO.NET driver for which, as far as I know, there is no good workaround. The first is that the SQL processor can’t handle hard-coded values which contain the "at sign", such as:
SELECT * FROM MY.TABLE WHERE THE.KEY = "DAN@WORK"
Depending on the structure of your data you may be able to get at the data by using a wildcard instead
SELECT * FROM MY.TABLE WHERE THE.KEY LIKE "DAN%WORK"
The other bug is that zero-length numeric fields such as the one in attribute 5 below will result in an “Input string was not in a correct format” error (that funny little accented character is ASCII 253, the multivalue delimiter):
0001: SMITH 0002: 1414 W. 8TH 0003: DENVER 0004: CO 0005: V2001ýýC8181 0006: 200ý3599ý1050
This latter bug was fixed by IBM in the recently released Fix Pack 3, but if you have users on earlier releases there is a workaround you can implement in your code, as explained later in the article.
7) Last, but not least, multivalues. As described in my previous article there are a few different ways to configure your dictionary to return multivalues, but the method that IBM recommends is to list the multivalued fields in a special "association" dictionary entry that looks like this:
DETAILS
001 PH ASSOCIATION OF ORDER DETAIL FIELDS
002 ORDER.IDS ORDER.AMOUNTS
The advantage of this approach is that you can return the items within the multivalued field as if they were separate columns, which makes the data a lot easier to work with. The disadvantage is that you’ll have to puzzle out the syntax for a join with a "virtual table". If the above field DETAILS was defined in the dictionary of a table named CUSTOMERS, then a SQL statement to return a list of order IDs and amounts would be:
SELECT a.KEY.FULL, ORDER.IDS, ORDER.AMOUNTS FROM CUSTOMERS a JOIN CUSTOMERS_DETAILS b ON a.KEY.FULL = b.KEY.FULL
Since the dictionary field that is automatically added for the primary key, "@ID", can’t be used in SQL statements, you’ll have to add one yourself in order to use it in the JOIN — in the above example I added a field named KEY.FULL to CUSTOMERS.
If by this point you’re fully freaked out by the UniVerse way of implementing SQL, then I’ve got some good news for you: the code itself is pretty much plain vanilla and won’t require much explanation. 
Before you start coding, you’ll need to add a reference to the IBM.Data.DB2 DLL to your project References list, as shown at the right. You’ll also need to add "IBM.Data.DB2" to your list of namespaces:
using IBM.Data.DB2;
The process of building a connection string is quite similar to other databases like SQL Server. You’ll need to set the Server, User, Password and Database (which is the UniVerse account name). In addition, you need to set two less familiar properties — ServerType and Pooling:
private string providerName = "IBM.Data.DB2"; private DbConnectionStringBuilder builder; private DbConnection conUniVerse; builder = new DbConnectionStringBuilder(); builder["Server"] = txtServer.Text.Trim(); builder["User ID"] = txtUserID.Text.Trim(); builder["Password"] = txtPassword.Text.Trim(); builder["ServerType"] = "universe"; builder["Pooling"] = "false"; builder["Database"] = txtAccount.Text.Trim(); string strConnectionString = builder.ConnectionString; DbProviderFactory m_provider = DbProviderFactories.GetFactory(providerName); conUniVerse= m_provider.CreateConnection(); conUniVerse.ConnectionString = strConnectionString; conUniVerse.Open();
You’ll then need to create an ADO Data Adapter and feed it the SQL statement.
DbProviderFactory factory = DbProviderFactories.GetFactory(providerName); DbDataAdapter adapter = factory.CreateDataAdapter(); adapter.FillError += new FillErrorEventHandler(adapter_FillError); adapter.SelectCommand = DB_GetCommand(strSQL);
Lastly, you create an ADO Dataset to hold the results of the query, then bind that Dataset to a grid on your form to display the data:
DataSet dsData = new DataSet(); adapter.Fill(dsData , "MyData"); bindingSource1.DataSource = dsData ; // bindingSource1 is a BindingSource object that I dragged from the Toolbox onto my form bindingSource1.DataMember = "MyData"; gridData.DataSource = bindingSource1; // gridData is a DataGridView object on my form conUniVerse.Close();
You may have noticed that I added a FillError event handler to my adapter. This is a workaround for the zero-length multivalue problem that I mentioned earlier in the article. In the error handler, you can examine the Exception’s properties and, if it appears to be the zero-length multivalue error, set the e parm’s Continue property to true.
void adapter_FillError(object sender, FillErrorEventArgs e)
{
if (e.Errors.Message.Contains("Input string was not in a correct format"))
e.Continue = true;
}
This will result in the dataset being filled, but without the multivalued " virtual record" that contained the zero-length value. If the zero-length value is just bad data then that’s probably what you want — otherwise, you’ll need Fix Pack 3.
Whew! That might seem like a lot of work to read some data into a grid, but it’s stable, it’s pretty fast, and it’s still a lot less coding than the only other stable and fast UniVerse API out there, UniVerse Objects. Once you’ve learned the ropes, UniVerse is now a viable database option for .Net development.





