Archive

Archive for the ‘ORM’ Category

IronRuby and the Entity Framework - Part 2.

March 11th, 2009 Simon Segal 1 comment

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

Lazy Loading and the Entity Framework. How long I can go on like this?

March 5th, 2009 Simon Segal 4 comments

In more recent times I have spent a fair slice of time looking at how to get lazy loading working in the Entity Framework (without using the codeplex solution). Oddly, the driver for this was to get Fetching Strategies implemented for the Entity Framework and not the other way around and I have devoted a quite a few posts recently to that.

If you have followed the story until now, then you will know that I developed a method of transparently lazy loading by using some AOP style trickery and weaving code into the Entities themselves. I did say that I wasn’t going to post on this but it will become apparent why I chose to liberally change my mind about that as we move through this post. Currently the way to have your entity ‘opt’ into lazy loading (with my code), is to decorate it with an attribute in the partial class representation of the Entity itself.

[LazyLoad("Customer", AttributeTargetMembers = @"regex:(Customer$)")]
[LazyLoad("Order_Details", AttributeTargetMembers = @"regex:(Order_Details$)")]
public partial class Order : IFetchable
{
    private IFetchingStrategy _strategy;
    public IFetchingStrategy FetchingStrategy
    {
        get { return _strategy; }
        set { _strategy = value; }
    }
}
Note that this attribute is already written and part of the code download, you don’t have to write any PostSharp attributes yourself to get the code to work. Once having applied the attribute and compiled, PostSharp kicks in and weaves code where it’s directed, in this case the Order entities Customer and Order_Details properties. A look at the code in Reflector confirms this:
Post Sharp Code Weave into Entity
Now cool as PostSharp is, this is not a job I was hoping to have to have ever used it for. Entity Framework shouldn’t need that much work for transparent lazy loading and we are promised that will change in a later (next?) version. The lazy loading however is only part of the story. As much as I want transparent Lazy Loading OOTB, I equally need the Eager Loading story to be dealt with. As I have said throughout this series of posts, part of the fetching strategy problem lies in the disconnect between Lazy and Eager fetching and something tells that I will still be rewriting this solution for a later version of Entity Framework.

While we are waiting…..

This solution isn’t proven in battle and needs a lot more work to verify it’s bona fides, but I will push it forward on very small, low risk projects to see how it pans out. I for one really want the Entity Framework to ‘make good’ and reach the hearts and minds of the POCO and DDD audience into the bargain. The question is how long am I prepared to wait and ‘go via the cape’?
 

Step by Step

  • Download the code
  • Copy the LazyLoadAttribute.cs file into your project with an entity model
  • Reference the PostSharp.Laos, PostSharp.Public libraries.
  • Reference the Org.TechAvalanche.Orm.Repository library
  • Decorate the Partial class representation of your Entity with the LazyLoad attribute (copied in the second step) and your done. Write your fetching strategies, Repositories and Specifications and away you go.

I will soon follow with an Item Template for VS.Net that creates the attribute file and makes the references for you automatically.

Share/Save/Bookmark

Entity Framework, Repositories, Specifications and Fetching Strategies Part 10.0 (or Lazy Loading and Fetching Strategies again, with feeling)!

February 24th, 2009 Simon Segal 2 comments

One of the main goals of the previous post in this series was to take a look at Fetching Strategies for the Entity Framework and how we might be able to achieve them with a single approach, particularly in light of the fact that the Entity Framework’s  Lazy Loading (if we can call it that) is enlisted explicitly and from an API perspective it’s completely removed from how it manages eager fetching.

When we first looked at the Fetching Strategy the implementation looked something like this:

public class MultiLevelMixedStrategy : IFetchingStrategy
{
    private readonly IList<FetchingIntention> _intentions =
        new List<FetchingIntention>();

    public MultiLevelMixedStrategy()
    {
        this.Intentions.Add(new FetchingIntention(“Orders”,
                            FetchMode.Eager));
        this.Intentions.Add(new FetchingIntention(“Orders.Order_Details”,
                            FetchMode.Eager));
        this.Intentions.Add(new FetchingIntention(“Product”,
                            FetchMode.Lazy));
    }

    public IList<FetchingIntention> Intentions
    {
        get { return _intentions; }
    }
}

The next iteration had seen to it that the magic strings were not the only option when we want to new up a FetchingIntention; so lambda expressions became part of the menu. This iteration had our FetchingStrategy looking like this:

public class RoleStrategy : IFetchingStrategy<ICustomerMakePrefered>
{
    private readonly IList<FetchingIntention> _intentions =
        new List<FetchingIntention>();

    public RoleStrategy()
    {
        var order_intention =
            FetchingIntention.CreateInstance
            <Customer, EntityCollection<Order>>
            (c => c.Orders, FetchMode.Eager);

        var order_details_intention = order_intention.And(
            FetchingIntention.CreateInstance
            <Order, EntityCollection<Order_Detail>>
            (o => o.Order_Details, FetchMode.Eager));

        var product_intention = FetchingIntention.CreateInstance
            <Order_Detail, Product>
            (od => od.Product, FetchMode.Lazy);

        this.Intentions.Add(order_intention);
        this.Intentions.Add(order_details_intention);
        this.Intentions.Add(product_intention);
    }

    public IList<FetchingIntention> Intentions
    {
        get { return _intentions; }
    }
}

As I said in the previous post, the compounding of arguments that would ultimately build up the string used in an ObjectQuery<T>.Include(”object.relations.etc”) method call, was achieved by chaining FetchingIntention objects together with a fluent interface. For example:

var intent = order_intention
            .And(order_details_intention)
            .And(product_intention);

Finally I want to mention that whilst we did get Lazy Loading implemented as well (without it there is no support for the Fetching Strategies), I haven’t made a point of highlighting it because ultimately I find it reasonably uninteresting. You can look deeper into how the Lazy Loading was implemented (by looking at the code) with the aid of post sharp and some AOP’ish post compile weaving.

Share/Save/Bookmark

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