Showing posts with label NHibernate. Show all posts
Showing posts with label NHibernate. Show all posts

Friday, September 17, 2010

Implementing a ‘Money’ type in an ASP.NET MVC and NHibernate application.

Years ago I read Kent Beck’s seminal Test Driven Development. The first third of the book is a complete worked example of building a Currency type using TDD and I remember thinking at the time that this was an incredibly powerful technique. Rather than using basic data types -  int, string, DateTime - we could define what we actually meant. Rather than having a property Age of type int, we would define an Age type. Rather than two string properties we could define a Name type. One of the factors in moving Suteki Shop from Linq-to-SQL to NHibernate was NHibernate’s support for more complex finer-grained mapping.

When I first hacked together Suteki Shop, I used the decimal type everywhere I needed to represent money. This has mostly worked well for the simple scenario where a shop only has a single currency and that currency is sterling (£). But anyone wanting to sell in US dollars had to find every one of the many instances of “£” and replace them with “$”, and if you wanted to do something fancy with multiple currencies, you would have been out of luck. What I needed was a Money type. It’s not a trivial refactoring. Here are the steps I needed to take:

  1. Create a Money type that behaved as far as possible like a .NET numeric type.
  2. Create an ASP.NET MVC IModelBinder that knew how to bind the Money type.
  3. Create an NHibernate IUserType that knew how to persist the Money type.
  4. Change every point in the code that was using decimal to represent money to use the Money type instead.

Create a Money type

I wanted to create a Money type that would behave nicely when I did arithmetic with it. So I wanted to be able to write expression like this:

var x = new Money(43.5M);
var result = x * 3 + x/2 - 4;
result.Amount.ShouldEqual(148.25M);

To achieve this you have to write a lot of operator overloads for all combinations of operator, Money <-> Money, Money <-> decimal and decimal <-> Money. I won’t bore you, if you want to see the gory details, you can view the code here.

I also wanted my Money type to include the currency symbol when ToString was invoked, so I would get “£12.54” rather than “12.54”, but I found that this caused lots of problems with HTML forms and the default behaviour of the MVC HtmlHelper extensions. In the end I left ToString returning the number without the currency symbol and implemented a new method ToStringWithSymbol with it included. It feels like a horrible hack though.

I also overrode the equality operator, GetHashCode and Equals so make Money behave as expected in equality operations.

public class Money
{
    public decimal Amount { get; private set; }

    public Money(decimal amount)
    {
        Amount = amount;
    }

    public static string Symbol
    {
        get { return "£"; }
    }

    public static Money Zero
    {
        get { return new Money(0M);}
    }

    public override string ToString()
    {
        return Amount.ToString("0.00");
    }

    public string ToStringWithSymbol()
    {
        return Amount.ToString(Symbol + "0.00");
    }

    public override int GetHashCode()
    {
        return Amount.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        var otherMoney = obj as Money;
        if (otherMoney == null) return false;
        return Amount.Equals(otherMoney.Amount);
    }

    public bool Equals(Money otherMoney)
    {
        if (otherMoney == null) return false;
        return Amount.Equals(otherMoney.Amount);
    }

    public static bool operator ==(Money a, Money b)
    {
        // If both are null, or both are same instance, return true.
        if (ReferenceEquals(a, b))
        {
            return true;
        }

        // If one is null, but not both, return false.
        if (((object)a == null) || ((object)b == null))
        {
            return false;
        }

        return a.Amount == b.Amount;
    }

    public static bool operator !=(Money a, Money b)
    {
        return !(a == b);
    }
    
    .....
}

Create an ASP.NET MVC IModelBinder

I wanted any of my forms that posted money values to work seamlessly when binding to entities with Money properties. For this to work I had to implement an IModelBinder for Money.

Creating the ModelBinder was pretty straightforward since I was just binding to a simple type.

public class MoneyBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (!typeof (Money).IsAssignableFrom(bindingContext.ModelType))
        {
            throw new SutekiCommonException(
                "MoneyBinder has attempted to bind to type '{0}', but may only bind to Money",
                                            bindingContext.ModelType);
        }

        var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

        try
        {
            var decimalValue = (decimal)valueProviderResult.ConvertTo(typeof(decimal));
            return new Money(decimalValue);
        }
        catch (Exception exception)
        {
            bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Not a valid price.");
            return null;
        }
    }
}

But it could have been much easier. The IModelBinder interface doesn’t make it easy to work out how you are supposed to do simple binding. A SimpleModelBinder<T> with an abstract method like: T BindSimpleModel(string value) would have been nice.

The MoneyBinder is registered as a binder for the Money type in Global.asax.cs:

ModelBinders.Binders.Add(typeof(Money), new MoneyBinder());

Create an NHibernate IUserType

I wanted any entity that had a property of type Money to get automatically persisted by NHibernate as a numeric value. To do this I needed an IUserType. This tells NHibernate how to persist your custom type.

To create the NHibernate IUserType I borrowed Darrell Mozingo’s excellent BaseImmutableUserType<T>. With this it’s fairly straightforward:

public class MoneyUserType : BaseImmutableUserType<Money>
{
    public override object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var amount = ((decimal?)NHibernateUtil.Decimal.NullSafeGet(rs, names[0]));
        return amount.HasValue ? new Money(amount.Value) : Money.Zero;
    }

    public override void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        var moneyObject = value as Money;
        object valueToSet;

        if (moneyObject != null)
        {
            valueToSet = moneyObject.Amount;
        }
        else
        {
            valueToSet = DBNull.Value;
        }

        NHibernateUtil.Decimal.NullSafeSet(cmd, valueToSet, index);
    }

    public override SqlType[] SqlTypes
    {
        get
        {
            return new[]
                   {
                       SqlTypeFactory.Decimal
                   };
        }
    }
}

To register the MoneyUserType I just added a convention to my Fluent NHibernate setup:

public class FluentNHibernateConfigurationBuilder : IConfigurationBuilder
{
    ....

    public static void ConfigureMappings(MappingConfiguration mappingConfiguration)
    {
        mappingConfiguration.FluentMappings
            .AddFromAssembly(typeof (ProductMap).Assembly)
            .Conventions.Add(
                ForeignKey.EndsWith("Id"),
                PrimaryKey.Name.Is(x => x.EntityType.Name + "Id"),
                DefaultCascade.None(),
                new MoneyConvention());
    }
}

public class MoneyConvention : UserTypeConvention<MoneyUserType>{}

Change every point in the code that was using decimal to represent money to use the Money type instead

I had naively hoped that a good enough Money class would allow me to just change the type of money properties from decimal to Money and have done with it. But even with the operator overloading I found that there were many places where I needed to add ‘.Amount’ to make the code behave. I could have implemented an implicit cast, but I don’t like not knowing where types are being converted. I’ve found in the past that it can lead to subtle, hard to find, bugs.

What I have now is a single point where I can change the way money behaves in Suteki Shop. Providing multi-currency or changing the behaviour of money in any way should be far easier. And if you simply want to take Suteki Shop and sell in Dollars, Yen or Euros, it’s now just a single line change to the code. And yes, configurable currencies will come very soon.

Some thoughts on the C# type system

This was far more work than it needs to be and is a clear example of the deficiencies of the C# type system. With Haskell’s type classes or Scalar’s implicits it would have been possible to create a new numeric type without having the change ripple through the entire application. The Scalar implicit is a very interesting idea and would surely be a very cool addition to the C# type system. Anders?

Friday, August 06, 2010

NHibernate Linq Eager Fetching

The new NHibernate Linq provider provides eager fetching out of the box. Here’s how you do it:

var customers = session.Query<Customer>().Fetch(c => c.Orders).ToList();

Note, Query<T> is an extension method in the NHibernate.Linq namespace.

The statement above will cause the following SQL to be executed:

select customer0_.CustomerId   as CustomerId0_0_,
       orders1_.OrderId        as OrderId3_1_,
       customer0_.CompanyName  as CompanyN2_0_0_,
       customer0_.ContactName  as ContactN3_0_0_,
       customer0_.ContactTitle as ContactT4_0_0_,
       customer0_.Address      as Address0_0_,
       customer0_.City         as City0_0_,
       customer0_.Region       as Region0_0_,
       customer0_.PostalCode   as PostalCode0_0_,
       customer0_.Country      as Country0_0_,
       customer0_.Phone        as Phone0_0_,
       customer0_.Fax          as Fax0_0_,
       orders1_.CustomerId     as CustomerId3_1_,
       orders1_.EmployeeId     as EmployeeId3_1_,
       orders1_.OrderDate      as OrderDate3_1_,
       orders1_.RequiredDate   as Required5_3_1_,
       orders1_.ShippedDate    as ShippedD6_3_1_,
       orders1_.ShipVia        as ShipVia3_1_,
       orders1_.Freight        as Freight3_1_,
       orders1_.ShipName       as ShipName3_1_,
       orders1_.ShipAddress    as ShipAdd10_3_1_,
       orders1_.ShipCity       as ShipCity3_1_,
       orders1_.ShipRegion     as ShipRegion3_1_,
       orders1_.ShipPostalCode as ShipPos13_3_1_,
       orders1_.ShipCountry    as ShipCou14_3_1_,
       orders1_.CustomerId     as CustomerId0__,
       orders1_.OrderId        as OrderId0__
from   Customers customer0_
       left outer join Orders orders1_
         on customer0_.CustomerId = orders1_.CustomerId

As you can see a single statement returns the customer and all the customer’s orders, just as expected.

Note that if you want to mix Fetch with other clauses, Fetch must always come last. So for example:

var customers = session.Query<Customer>().Fetch(c => c.Orders).Where(c => c.CustomerId == "ANATR").ToList();

Will throw a nasty parse exception:

Test 'NHibernate.Test.Linq.EagerLoadTests.WhereWorksWithFetch' failed: System.NotSupportedException : Specified method is not supported.

But this will work fine:

var customers = session.Query<Customer>().Where(c => c.CustomerId == "ANATR").Fetch(c => c.Orders).ToList();

Be careful not to eagerly fetch multiple collection properties at the same time. Although this statement will work fine:

var employees = session.Query<Employee>()
    .Fetch(e => e.Subordinates)
    .Fetch(e => e.Orders).ToList();

It executes a Cartesian product query against the database, so the total number of rows returned will be the total Subordinates times the total orders. Ayende discusses this behaviour here.

You can fetch grandchild collections too. Here we use ‘FetchMany’ and ‘ThenFetchMany’:

var customers = session.Query<Customer>()
    .FetchMany(c => c.Orders)
    .ThenFetchMany(o => o.OrderLines).ToList();

Which produces the following SQL:

select customer0_.CustomerId    as CustomerId0_0_,
       orders1_.OrderId         as OrderId3_1_,
       orderlines2_.OrderLineId as OrderLin1_4_2_,
       customer0_.CompanyName   as CompanyN2_0_0_,
       customer0_.ContactName   as ContactN3_0_0_,
       customer0_.ContactTitle  as ContactT4_0_0_,
       customer0_.Address       as Address0_0_,
       customer0_.City          as City0_0_,
       customer0_.Region        as Region0_0_,
       customer0_.PostalCode    as PostalCode0_0_,
       customer0_.Country       as Country0_0_,
       customer0_.Phone         as Phone0_0_,
       customer0_.Fax           as Fax0_0_,
       orders1_.CustomerId      as CustomerId3_1_,
       orders1_.EmployeeId      as EmployeeId3_1_,
       orders1_.OrderDate       as OrderDate3_1_,
       orders1_.RequiredDate    as Required5_3_1_,
       orders1_.ShippedDate     as ShippedD6_3_1_,
       orders1_.ShipVia         as ShipVia3_1_,
       orders1_.Freight         as Freight3_1_,
       orders1_.ShipName        as ShipName3_1_,
       orders1_.ShipAddress     as ShipAdd10_3_1_,
       orders1_.ShipCity        as ShipCity3_1_,
       orders1_.ShipRegion      as ShipRegion3_1_,
       orders1_.ShipPostalCode  as ShipPos13_3_1_,
       orders1_.ShipCountry     as ShipCou14_3_1_,
       orders1_.CustomerId      as CustomerId0__,
       orders1_.OrderId         as OrderId0__,
       orderlines2_.OrderId     as OrderId4_2_,
       orderlines2_.ProductId   as ProductId4_2_,
       orderlines2_.UnitPrice   as UnitPrice4_2_,
       orderlines2_.Quantity    as Quantity4_2_,
       orderlines2_.Discount    as Discount4_2_,
       orderlines2_.OrderId     as OrderId1__,
       orderlines2_.OrderLineId as OrderLin1_1__
from   Customers customer0_
       left outer join Orders orders1_
         on customer0_.CustomerId = orders1_.CustomerId
       left outer join OrderLines orderlines2_
         on orders1_.OrderId = orderlines2_.OrderId

Once again, exactly as expected.

Happy Fetching!

Friday, April 16, 2010

Moving Suteki Shop from Linq-to-SQL to NHibernate

I’ve finished getting the basic features of Suteki Shop running with NHibernate. Anyone who’s been following this project knows that it was originally written with Linq-to-SQL. Linq-to-SQL worked fine for the initial iterations of Suteki Shop, but there are lots of things I wanted to do with the project that would have been hard or impossible to do without the move.

Linq-to-SQL not a true ORM in the sense that it doesn’t support persistence ignorance, it’s more a object based projection of a relational database. Each class directly represents a table row, including foreign keys. One of the main pain points in the transition was removing all the application code that referenced these foreign keys and replacing them with object references instead. So for example, instead of changing the int value of Contact.CountryId I would change the actual referenced entity, Contact.Country.

The other place where I had to do lots of work was in my Linq queries. The NHibernate trunk now has a native Linq provider written by Steve Strong, so you can write:

var customer = session.Query<Customer>().Where(c => c.Name == "Fred").FirstOrDefault();

The main difference between the Linq-to-SQL provider and the NHiberante one is in the way they treat expressions that they don’t understand. Linq-to-SQL will translate as much of the expression that it can to SQL, get the result, and then allow Linq-to-objects to do the rest. The NHibernate provider will throw an exception saying that it doesn’t understand the expression. There are pros and cons to both approaches. Linq-to-SQL will always give you what you want, but maybe in an inefficient way you weren’t expecting, whereas NHibernate will force you to think about how you structure your queries. There are no surprises, but it’s a mark against persistence ignorance. Right now, I’m liking the NHibernate no surprises approach.

Whilst doing the conversion I ran into a problem with the OfType<T>() Linq extension method. I was using it in several places but NHibernate complained that it didn’t support it. I tweeted about it and almost immediately Steve Strong replied that it should be easy to implement. The next day he committed it to the NHibernate trunk and my queries all worked.

steve-strong

Steve Strong, you are an awesome open source hero!

One of my major regrets with the way that I originally wrote Suteki Shop is binding views to entities, rather than using a view model. At first this can seem like an easy-win, but doing this work showed how can soon lead to all sorts of difficulties. Displaying the view model in the view is not so much of a problem - except in entity loading overhead. The problems mostly manifest themselves at the binding stage. I extended the ASP.NET MVC DefaultModelBinder to work with NHibernate entities, and it mostly works, but I spent far too much time resolving tricky binding issues with complex object graphs. I would have made my life much easier by binding to a nice flat view model and then manually mapping that to my entities.

Persistence ignorance is a dream, a nirvana, where we’d love to be, but no ORM will give you true persistence ignorance. NHibernate is far better in this regard than Linq-to-SQL, but you still have to do things the NHibernate way. Your ORM will hugely influence the way you build your application and although the persistence ignorance ideal should mean you can swap them with little difficulty, moving from Linq-to-SQL to NHibernate was a major piece of work, far more than I expected.

Friday, January 09, 2009

Integrating Fluent NHibernate and the Windsor NHibernate Facility

Our current project uses NHibernate as its ORM. Until recently we've been using the default hbm mapping files, but we've been suffering for some time from Fluent NHibernate envy. So now we've decided to take the plunge and migrate our project to code based mapping. My esteemed colleague Keith Bloom has been doing most of the work for this, and this post is simply me taking a free ride on all his hard work. Thanks Keith :)

I'm not going to describe Fluent NHibernate here. You can check out the project page if you want to see what it's all about. Suffice to say that it's a really nice API to describe object-relational mapping. Once you've defined your mappings, it's a simple case of applying them to the NHibernate configuration with a handy extension method:

var cfg = new Configuration()
	.Configure()
	.LoadMappingAssembly(Assembly.LoadFrom("Name of assembly that contains your maps."));

However we're using Windsor's very convenient NHibernate integration facility in our project. It does all the configuration and session management for us, so we don't have to worry about it. The problem is, that because it handles it for us, there's not an immediately obvious place to access the configuration to apply the Fluent NHibernate mappings.

It turns out that the simplest way of doing this is to write your own implementation of IConfigurationBuilder. This is the NHibernate facility class that actually creates the NHibernate configuration:

public class FluentNHibernateConfigurationBuilder : IConfigurationBuilder
{
	public Configuration GetConfiguration(IConfiguration facilityConfiguration)
	{
	    var defaultConfigurationBuilder = new DefaultConfigurationBuilder();
	    var configuration = defaultConfigurationBuilder.GetConfiguration(facilityConfiguration);
             configuration.AddMappingsFromAssembly(Assembly.LoadFrom("Name of assembly that contains your maps."));
	    return configuration;
	}
}

Note that we're simply deferring the creation of the NHibernate configuration to the DefaultConfigurationBuilder and then adding the call to to AddMappingsFromAssembly before passing it on. All we have to do now is configure the facility to use our new configuration builder:

<facility id="nhibernate"
          isWeb="false"
          type="Castle.Facilities.NHibernateIntegration.NHibernateFacility, Castle.Facilities.NHibernateIntegration"
          configurationBuilder="Keith.WindsorNHibernate.Services.FluentNHibernateConfigurationBuilder, Keith.WindsorNHibernate">
  <factory id="nhibernate.factory">
    <settings>
      <item key="show_sql">true</item>
      <item key="connection.provider">NHibernate.Connection.DriverConnectionProvider</item>
      <item key="connection.driver_class">NHibernate.Driver.SqlClientDriver</item>
      <item key="dialect">NHibernate.Dialect.MsSql2005Dialect</item>
      <item key="connection.connection_string">Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True</item>
    </settings>
  </factory>
</facility>

Keith has kindly allowed me to post his test solution which you can download below. You'll need sqlexpress with a copy of Northwind to run it.

http://static.mikehadlow.com/Keith.WindsorNHibernate.zip

Monday, October 20, 2008

Mapping entities to multiple databases with NHibernate

The legacy application I'm currently replacing features multiple databases for some insane reason. Luckily it's quite easy to get NHibernate to do joins across databases so long as they are on the same server. The technique is detailed by Hector Cruz in this thread on the NHibernate forum. The trick is to specify the schema you are addressing in each mapping file. Because the schema name simply becomes a table prefix, you can also use it to specify cross database joins. So long as you follow good practice and have one mapping file per entity, it means that, in theory, each entity could be persisted to a different database. I've put together a little project to show this working using Northwind. You can download the code here:

http://static.mikehadlow.com/Mike.NHibernate.Multiple.zip

I took a backup of Northwind and then restored it to a new database so that I had a Northwind and a Northwind2. I'm going to get the Product entity from the Products table on Northwind and the Supplier from the Suppliers table in Northwind2. The great thing is that you only need a single connection string pointing to one database (in my case the original Northwind).

Here's the NHibernate configuration:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler,NHibernate" />
  </configSections>
  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
      <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
      <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
      <property name="connection.connection_string">Data Source=.\sqlexpress;Initial Catalog=Northwind;Integrated Security=True</property>
      <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
      <property name="show_sql">true</property>
      <mapping assembly="Mike.NHibernate.Multiple"/>
    </session-factory>
  </hibernate-configuration>
</configuration>

Nothing special here. I've just nominated the original Northwind database to be my  initial catalogue. Next I've got two entities, Product and Supplier:

namespace Mike.NHibernate.Multiple
{
    public class Product : Entity
    {
        public virtual string ProductName { get; set; }
        public virtual Supplier Supplier { get; set; }
    }
}
namespace Mike.NHibernate.Multiple
{
    public class Supplier : Entity
    {
        public virtual string CompanyName { get; set; }
    }
}

Once again pure persistence ignorance. You don't have to do anything special with your entities. Now, here's the trick: The mapping file for the Product entity specifies the schema as Northwind.dbo:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" schema="Northwind.dbo" >
  <class name="Mike.NHibernate.Multiple.Product, Mike.NHibernate.Multiple" table="Products">
    <id name="Id" column="ProductID" type="Int32">
      <generator class="identity" />
    </id>
    <property name="ProductName" />
    <many-to-one name="Supplier" class="Mike.NHibernate.Multiple.Supplier, Mike.NHibernate.Multiple" column="SupplierID" />
    
  </class>
</hibernate-mapping>

While the Supplier mapping file specifies Northwind2.dbo:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" schema="Northwind2.dbo" >
  <class name="Mike.NHibernate.Multiple.Supplier, Mike.NHibernate.Multiple" table="Suppliers">
    <id name="Id" column="SupplierID" type="Int32">
      <generator class="identity" />
    </id>
    <property name="CompanyName" />
  </class>
</hibernate-mapping>

Now, hey-presto! When I run this little console program to retrieve a Product from NHibernate, I get an object graph back with Product entities from Northwind and Supplier entities from Northwind2.

using System;
using NHibernate.Cfg;
namespace Mike.NHibernate.Multiple
{
    class Program
    {
        static void Main()
        {
            var configuration = new Configuration();
            configuration.Configure();
            var sessionFactory = configuration.BuildSessionFactory();
            var session = sessionFactory.OpenSession();
            var product = session.Load<Product>(1);
            Console.WriteLine("Product: {0}, Supplier: {1}", product.ProductName, product.Supplier.CompanyName);
        }
    }
}

NHibernate generates this SQL:

 

NHibernate: 
SELECT 
 product0_.ProductID as ProductID0_0_, 
 product0_.ProductName as ProductN2_0_0_, 
 product0_.SupplierID as SupplierID0_0_ 
FROM Northwind.dbo.Products product0_ 
WHERE product0_.ProductID=@p0; @p0 = '1'
NHibernate: 
SELECT 
 supplier0_.SupplierID as SupplierID1_0_, 
 supplier0_.CompanyName as CompanyN2_1_0_ 
FROM Northwind2.dbo.Suppliers supplier0_ 
WHERE supplier0_.SupplierID=@p0; @p0 = '1'

As you can see the Product was retrieved from Northwind and the Supplier from Northwind2. It's similar to when you do cross database joins in a stored procedure. The stored procedure has to live in a particular database, but because each table gets prefixed with it's database name the DBMS simply looks up the table in the referenced database.

Note that this trick is simply to deal with a legacy situation that I can't do much about. You really don't want to architect a system like this from scratch.

Tuesday, September 02, 2008

What's up with Linq to NHibernate?

With my current clients I'm building an MVC Framework application using NHibernate. I love NHibernate. Like all the best frameworks it just works for most common scenarios. I'm a new user, but I've been able to get up to speed with it very quickly. The power and flexibility of the mapping options make it easy to use with the legacy database that we're lumbered with. But the best thing about it though, is that it's built from the ground up for Domain Driven Development. This means it's possible to build a finely grained domain model unencumbered by data access concerns.

Seriously, if you're building .NET enterprise level business software and you haven't considered using NHibernate (or a competing ORM) you missing out on a huge productivity win.

Any ORM targeting .NET has to support Linq. Here the NHibernate story's not so good at the moment. The coding phenomena that is Ayende kicked off the first Linq to NHibernate implementation a while back. It was originally part of his Rhino Tools project and layered the Linq implementation on top of the NHibernate criteria API. This has now been moved to the NHibernate contrib project. The source is here:

http://sourceforge.net/projects/nhcontrib/

I've been using this in my current project, it works but only with the most straightforward queries. Anything tricky tends to fail and I've tended to go through a process of trial and error to find the right patterns. The problem seems to be mostly around the criteria API. It doesn't support a lot of the features that Linq requires, especially nested queries.

Recently a new NHibernate.Linq project has been started in the NHibernate trunk that takes a different approach. The authors are building SQL directly from the expression tree which obviously gives a lot more flexibility. The intention is to also to convert HQL to an expression tree thus having a single uniform query translation.

This is very exciting for NHibernate but there's going to be a hiatus while the new implementation evolves.

Thanks to Tuna Toksöz for the info.

Thursday, July 31, 2008

Playing with ADO.NET Data Services

I've recently been asked to architect and build my first major Silverlight based application. The requirement is for an on-line accommodation booking service for a large multi-site educational institution. As a fully paid up member of the ORM mafia I really wanted to have the same persistence ignorance on the client that I enjoy on the server. The only way I could see to achieve this was building some kind of generic web service front end on top of my repository model along with a client side proxy that behaved in much the same way. It looked like a lot of work.

Enter ADO.NET Data Services. The first thing I'll say about it, is that the name is really crap. I can't see how this has anything remotely to do with ADO.NET. Fundamentally it's a combination of a REST style service over anything that provides an IQueryable implementation, plus client side proxies that expose an IQueryable API. Here's a diagram:

ado_net_architecture

The Data Context can be any class that has a set of properties that return IQueryable<T> and that implements System.Data.Services.IUpdatable and System.Data.Services.IExpandProvider. The IQueryable<T> properties give the entities that are exposed by the REST API, IUpdatable supports (as you'd expect) posting updates back to the Data Context and IExpandProvider supports eagerly loading your object graph. The REST API has lazy load semantics by default, with all entity references being expressed as REST URLs.

It's very nicely thought out and easy to use. You simply create a new DataService<T> where T is your Data Context and the service auto-magically exposes your data as a RESTfull web service. I've been playing with the Northwind example. You just create a new Web Application in Visual Studio, add a "LINQ to SQL classes" item to your project and drag all the Northwind tables onto the LINQ-to-SQL designer. Next add an "ADO.NET Data Service" to the project then it's just a question of entering the name of the NorthwindDataContext class as the type parameter of the DataService:

ado_net_DataService

Note I've also added a ServiceBehaviour to show exception details in faults. Now when I hit F5 I get this error:

ado_net_ds_request_error

The way that ADO.NET Data Services works an entity's primary key is pretty simplistic. It just looks for properties that end with ID and gets confused by CustomerCustomerDemos. Shawn Wildermuth explains about this issue here. So I'll just remove everything from the designer except for tables with an obvious Id, and now I get this:

ado_net_toplevel

It's easy to explore the model by playing with the URL...

Currently only the much loved Entity Framework and LINQ to SQL provide a Data Context that you can use with this. David Hayden shows how to set up a LINQ to SQL project here. However, Shawn Wildermuth has been doing some great work exposing LINQ to NHibernate as a Data Service friendly Data Context. You can read about it here, here, here and here. His NHibernateContext is now part of the LINQ to NHibernate project. My project is using NHibernate as it's ORM, so I'll posting more about this soon.

You can download my sample using LINQ to SQL and Entity Framework here:

http://static.mikehadlow.com/Mike.DataServices.zip