Living in the Tech Avalanche Generation

A practitioner’s introspective on technology
Archive for March 11th, 2009

IronRuby and the Entity Framework - Part 2.

Last time we looked at taking IronRuby to the Entity Framework ‘via the cape’ so to speak, by building our Entity Model in a C# library that we consumed from IronRuby. That previous approach was a response to the lack of support in IronRuby to directly create an Entity Model as you would with C# or VB.NET. This is not to say however that is currently the only option available.

Enter Entity SQL or ESQL as it’s become known. It is ALMOST possible to enlist the services of the Entity Framework directly from IronRuby by putting Entity SQL to work. There are a few remaining impediments however, the ability to create an Entity Model directly in IronRuby and the lack of support for Generics are the most restricting. ESQL options are therefore limited in terms of writing code in IronRuby without the support for generics, however if we take the Entity SQL route, the only thing we are required to do with respect to interop, is host an ObjectContext<T> in an assembly built with a language that will support it. Entity SQL is a SQL like language that can be used as an alternative to LINQ to Entities. ESQL is a very rich language with a great deal functionality.

Let’s step through a fairly rudimentary look at using ESQL with IronRuby. Given the simplest of Northwind Entity Models as shown here:

simple_northwind_em

We would expect an ObjectContext with three ObjectQuery<T> property implementations.

public global::System.Data.Objects.ObjectQuery<Customers> Customers
{
    get
    {
        if ((this._Customers == null))
        {
            this._Customers =
                base.CreateQuery<Customers>(“[Customers]“);
        }
        return this._Customers;
    }
}

public global::System.Data.Objects.ObjectQuery<Order_Details> Order_Details
{
    get
    {
        if ((this._Order_Details == null))
        {
            this._Order_Details =
                base.CreateQuery<Order_Details>(“[Order_Details]“);
        }
        return this._Order_Details;
    }
}

public global::System.Data.Objects.ObjectQuery<Orders> Orders
{
    get
    {
        if ((this._Orders == null))
        {
            this._Orders =
                base.CreateQuery<Orders>(“[Orders]“);
        }
        return this._Orders;
    }
}

And that’s it, where done with creating our interop library that contains our ObjectContext / Unit of Work. Having created this Entity Model in a C# or VB.NET class library that we can ‘require’, we are now ready to use Entity SQL and IronRuby to engage the Entity Framework. Let’s start off by building a helper class to create the ObjectContext for us:

require ‘System.Windows.Forms, Version=2.0.0.0, ‘ +
‘Culture=neutral, PublicKeyToken=b77a5c561934e089′
require ‘D:/simon.segal/Local Working/Org.Techavalanche.IronEntities’ +
‘/Org.Techavalanche.EntityLibsForRuby/bin/Debug’ +
‘/Org.Techavalanche.EntityLibsForRuby.dll’
require ‘System.Data, Version=2.0.0.0, ‘ +
‘Culture=neutral, PublicKeyToken=b77a5c561934e089′
require ‘System.Data.DataSetExtensions, ‘ +
‘Version=3.5.0.0, Culture=neutral, ‘ +
‘PublicKeyToken=b77a5c561934e089′
require ‘System.Data.Entity, Version=3.5.0.0, ‘ +
‘Culture=neutral, PublicKeyToken=b77a5c561934e089′
require ‘System.Core, Version=3.5.0.0, ‘ +
‘Culture=neutral, PublicKeyToken=b77a5c561934e089′

class EntitySqlHelper 

    def initialize

    end

    def get_northwind_context

        providerName = “System.Data.SqlClient”;
        serverName = “boomer”;
        databaseName = “Northwind”;

        #Initialize the connection string builder for the
        #underlying provider.
        sqlBuilder = System::Data::SqlClient::
            SqlConnectionStringBuilder.new

        #Set the properties for the data source.
        sqlBuilder.DataSource = serverName;
        sqlBuilder.InitialCatalog = databaseName;
        sqlBuilder.IntegratedSecurity = true;

        #Build the SqlConnection connection string.
        providerString =
            sqlBuilder.ToString();

        #Initialize the EntityConnectionStringBuilder.
        entityBuilder = System::Data::EntityClient::
            EntityConnectionStringBuilder.new

        #Set the provider name.
        entityBuilder.Provider = providerName;

        #Set the provider-specific connection string.
        entityBuilder.ProviderConnectionString = providerString;

        #Set the Metadata location.
        entityBuilder.Metadata =
            “res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl”

        #get the connection string
        con = entityBuilder.ToString()

        #set up the ObjectContext
        session = Org::Techavalanche::
            EntityLibsForRuby::NorthwindEntities.new(con)

    end

end

Next comes the interesting part, writing some code to actually use the ObjectContext<T> and fetch some data.

#basic use of Entity SQL to obtain a 
#result set using the Entity Framework
begin

    h = EntitySqlHelper.new

    #gets the ObjectContext
    ctx = h.get_northwind_context

    #enumerate the Customers property of the context
    #directly. Customers is an ObjectQuery<T>, so we
    #do have some ability to use types that are generics
    #but we cant new any up explicitly as yet in IR
    ctx.Customers.each {|cust| puts cust.CustomerID}

    #lets have a look at the query string
    puts ctx.Customers.ToTraceString

    #now for some Entity SQL
    #create a connection
    connection = System::Data::EntityClient::
        EntityConnection.new(ctx.Connection.ConnectionString)

    #open a connection
    connection.Open

    #write some Entity SQL statement
    stmt = “select c.CustomerID, c.CompanyName “ +
        “from NorthwindEntities.Customers as c”

    #new up an EntityCommand
    cmd = System::Data::EntityClient::EntityCommand.new(stmt, connection)

    #get a DbDataReader to enumerate the results
    cmd_reader = cmd.ExecuteReader(System::Data::
        CommandBehavior.SequentialAccess)

    #print out the results from the query
    while cmd_reader.Read
        puts “Company ID: “ + cmd_reader.GetValue(0) + ” “ +
        “for Company Name: “ + cmd_reader.GetValue(1)
    end

end

Some things I would like to note about the code above:

  • Despite the lack of support for Generics, we do have support to new up Generic constructed types from an interop library that we write in other .NET languages.
  • ObjectQuery<T> implements IEnumerable<T> and has also benefited from having the implementation of the .each method we would expect from a collection.
  • Whilst lacking in the fluency of LINQ to Entities, Entity SQL does provide a reasonable solution in the short term for anybody who wants to include working with data as they spike their way to familiarity with IronRuby or perhaps your bold enough to use it in production scenarios at this early stage? Perhaps not?

The while loop at the bottom of code block above, produced this Ruby Console output in Visual Studio.

iron_ruby_entity_command_output

So, that’s a fairly rudimentary look at ESQL leveraged from IronRuby. The code from this post can be found here. Given my predilection toward the Entity Framework and my growing interest in IronRuby, I will continue this series with more up to date examples when (if) IronRuby begins to add the required support for this new data access platform.

Finally, I should mention that I am (again) using the FREE personal edition of Sapphire in Steel which plugs into Visual Studio 2008 quite nicely.

Share/Save/Bookmark

1 comment

Creative Commons Attribution-ShareAlike 2.5 Australia
Creative Commons Attribution-ShareAlike 2.5 Australia