Using JDBC from .NET

Introduction

If you've ever had to switch database drivers you know what a hassle that can be:

  • different performance issues.
  • different bugs.
  • different application behavior.

Many applications standardize on one or a few drivers for just that reason. If your environment is predominantly Java-based, your (JDBC) drivers won't help you much with .NET applications, unless you're willing to entrust your data health to the JDBC-ODBC bridge.

Exposing your Java data architecture to .NET can prevent driver-related problems or it can even allow you to add one of many free embedded Java database engines to your .NET application.

This is not the most compelling use case for most users, but we have a couple of customers who had such big problems with their database layers that they chose this integration route.

Architecture

Your .NET application uses generated in-process bindings to use the JDBC API. The following example code is from the bundled hsqldb example. hsqldb is a lightweight, embedded Java database, that you can now use within your .NET application.

using System;
using Codemesh.JuggerNET;
using Java.Lang;
using Java.Sql;
using Java.Util;


public class Application
{
	public static void	Main( string[] args )
	{
        //the database filename
        string	db_file_name_prefix = args.Length > 0 && !"-info".Equals( args[ 0 ].ToLower() ) ? args[ 0 ] : "test_db";

        //for now just terminate if we're invoked with the -info option
        if( args.Length > 0 && "-info".Equals( args[ 0 ].ToLower() ) ) 
            return;

        //the database connection
        Connection		conn = null;

        try
        {
            IJvmLoader	loader = JvmLoader.GetJvmLoader( true, true, TraceFacility.TraceJvm, TraceLevel.TraceErrors );

            // put the hsqldb classes (driver) on the bootclasspath to work around a 
            // limitation in the DriverManager when invoked from .NET
            loader.AppendBootClassPath = "../lib/hsqldb.jar;../../lib/hsqldb.jar";

            // make the JDBC driver available by preloading it
            Class.ForName("org.hsqldb.jdbcDriver");

            // connect to the database.   This will load the db files and start the
            // database if it is not alread running.
            // db_file_name_prefix is used to open or create files that hold the state
            // of the db.
            // It can contain directory names relative to the
            // current working directory
            conn = DriverManager.GetConnection( "jdbc:hsqldb:" + db_file_name_prefix,
                                                "sa",                     // username
                                                "");                      // password

            // create a table and insert some entries
            // this will only worl the first time and throw an exception every following time
            // because the table already exists 
            try
            {
                Update( conn, "CREATE TABLE sample_table ( id INTEGER IDENTITY, str_col VARCHAR(256), num_col INTEGER)");

                // add some rows - will create duplicates if run more then once
                // the id column is automatically generated
                Update( conn, "INSERT INTO sample_table(str_col,num_col) VALUES('Ford', 100)");
                Update( conn, "INSERT INTO sample_table(str_col,num_col) VALUES('Toyota', 200)");
                Update( conn, "INSERT INTO sample_table(str_col,num_col) VALUES('Honda', 300)");
                Update( conn, "INSERT INTO sample_table(str_col,num_col) VALUES('GM', 400)");
                Update( conn, "INSERT INTO sample_table(str_col,num_col) VALUES('BMW', 80)");
                Update( conn, "INSERT INTO sample_table(str_col,num_col) VALUES('Mercedes-Benz', 60)");
                Update( conn, "INSERT INTO sample_table(str_col,num_col) VALUES('VW', 800)");
            }
            catch( SQLException sqle )
            {
                Console.WriteLine( sqle.Message );
            }
            catch( Throwable it )
            {
                Console.WriteLine( it.StackTrace );
            }
            catch( System.Exception ie )
            {
                Console.WriteLine( ie.ToString() );
            }

			try
			{
				Console.WriteLine( "---------------" );

				// do a query
				Query( conn, "SELECT * FROM sample_table WHERE num_col < 250");

				Console.WriteLine( "---------------" );

				// do another query
				Query( conn, "SELECT str_col FROM sample_table WHERE num_col >= 100");

				Console.WriteLine( "---------------" );

				conn.Close();
			}
			catch( Throwable t )
			{
				Console.WriteLine( "Caught throwable of type {0}", t.GetClass().GetName() );
				Console.WriteLine( t.ToString() );
				return;
			}
			catch( JuggerNETFrameworkException jnfe )
			{
				Console.WriteLine( "Caught framework exception" );
				Console.WriteLine( jnfe.Message );
				Console.WriteLine( jnfe.StackTrace );
				return;
			}

			return;
		}
		catch( System.Exception se )
		{
			Console.WriteLine( se.ToString() );
		}
	}

	public static void	Dump( ResultSet rs )
	{
		// the order of the rows in a cursor
		// are implementation dependent unless you use the SQL ORDER statement
		ResultSetMetaData meta   = rs.GetMetaData();
		int               colmax = meta.GetColumnCount();
		int               i;
		object            o = null;

		// the result set is a cursor into the data.  You can only
		// point to one row at a time
		// assume we are pointing to BEFORE the first row
		// rs.next() points to next row and returns true
		// or false if there is no next row, which breaks the loop
		for (; rs.Next(); ) 
		{
			for (i = 0; i < colmax; ++i) 
			{
				o = rs.GetObject(i + 1);    // Is SQL the first column is indexed

				// with 1 not 0
				Console.Write( "{0} ", o.ToString() );
			}

			Console.WriteLine( "" );
		}
	}


	public static void Update( Connection conn, String expression)
	{
		Statement st = null;

		st = conn.CreateStatement();    // statements

		int i = st.ExecuteUpdate(expression);    // run the query

		if (i == -1) 
		{
			Console.WriteLine( "db error : {0}", expression );
		}

		st.Close();
	}


	public static void		Query( Connection conn, String expression )
	{
		Statement st = null;
		ResultSet rs = null;

		st = conn.CreateStatement();         // statement objects can be reused with

		// repeated calls to execute but we
		// choose to make a new one each time
		rs = st.ExecuteQuery(expression);    // run the query

		// do something with the result set.
		Dump(rs);
		st.Close();    
		// NOTE!! if you close a statement the associated ResultSet is closed 
		// too so you should copy the contents to some other object.
		// the result set is invalidated also  if you recycle an Statement
		// and try to execute some other query before the result set has been
		// completely examined.
	}
}


Copyright 2006-2011 by Codemesh, Inc., ALL RIGHTS RESERVED

:
jdbc .net
home products support customers partners newsroom about us contact us