Showing posts with label orm. Show all posts
Showing posts with label orm. Show all posts

Wednesday, 16 January 2008

Viewing the SQL generated by NHibernate

There are at least a couple of ways to view the SQL generated by NHibernate. The easiest way is probably to use the hibernate.show_sql configuration property to dump it all to Console.Out:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section
       name="nhibernate"
       type="System.Configuration.NameValueSectionHandler, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
    />
  </configSections>  
  <nhibernate>
    <add
      key="hibernate.connection.provider"
      value="NHibernate.Connection.DriverConnectionProvider"
    />
    ...
    <add key="hibernate.show_sql" value="true" />
  </nhibernate>
</configuration>

Another way is to configure log4net. NHibernate logs a wealth of information, but you can restrict it to just the generated SQL by doing the following:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section
       name="nhibernate"
       type="System.Configuration.NameValueSectionHandler, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
    />
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
  </configSections>  
  <nhibernate>
    ...
  </nhibernate>  
  <log4net>
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date - %message%newline"/>
      </layout>
    </appender>
    <!-- NHibernate.SQL logs all generated SQL (see update below) -->
    <logger name="NHibernate.SQL" additivity="false">
      <level value="DEBUG" />
      <appender-ref ref="ConsoleAppender" />
    </logger>
    <!-- 
      NHibernate.Loader.Loader logs diagnostic stuff and SELECTs. 
      You can use either logger, or both, depending on you needs.
    -->
    <logger name="NHibernate.Loader.Loader" additivity="false">
      <level value="INFO" />
      <appender-ref ref="ConsoleAppender" />
    </logger>
  </log4net>
</configuration>

Update: Kenneth Xu helpfully pointed out in the comments that NHibernate.SQL is better for this than NHibernate.Loader.Loader (which this post originally used), providing more information on both the queries and the updates generated by NHibernate. Dave Perry also pointed out that NHibernate.SQL logs at DEBUG level rather than INFO. Thanks Kenneth and Dave!

This configuration means that anything logged from the NHibernate.SQL class will go through the logger with the matching name. This class happens to log NHibernate-generated SQL as DEBUG messages. You can also use NHibernate.Loader.Loader, which logs various diagnostics and SELECTs.

To get this log4net configuration to work, I had to make sure the following code was executed once in the relevant AppDomain: log4net.Config.XmlConfigurator.Configure();. In my case, I chucked it in the test fixture setup. Calling it multiple times doesn't seem to break anything, but you really only need to call it once to pickup your configuration.

Unlike the hibernate.show_sql option, this does not show the values of the parameters passed for substitution in each SQL statement.

Viewing logs in NUnit

NUnit has a Log tab that lists log4net logging information, as well as displaying Console.Out and Console.Error. If you go to the Tools menu --> Options -->Text Output, you can get NUnit to "Display TestCase Labels" for each test. Combined with the logging options above, you can then get a nice view of the SQL used for each of your tests.

NUnit displaying NHibernate generated SQL

More information

I found this post from Mike Nichols a very helpful reference on NHibernate logging. There is also some official documentation on the subject.

Tuesday, 8 January 2008

Messing around with Castle ActiveRecord

This post is part of a small series on .NET ORM tools. You can find the rest of them here.

After getting a surprise kick, I got a suggestion from Josh to take a look at the Castle ActiveRecord project. So here goes, using Castle 1.0 RC3.

Scene refresher

I have a table of suppliers, and a table of states (or provinces, territories, prefectures etc.). Both suppliers and states have names, which are stored as strings/varchars, and IDs, which are stored as Guids/uniqueidentifiers. Each supplier can service many states. So we have a simple many-to-many relationship between the two main entities. It looks a bit like this:

I am using Aussie states for my tests, so I have populated the State table with the following names: NSW, VIC, QLD, TAS, SA, WA, ACT, NT.

Setting up Castle ActiveRecord

I created a new C# class library project, then added references to:

  • Castle.ActiveRecord.dll
  • Castle.Core.dll
  • Castle.Components.Validator.dll
  • Castle.DynamicProxy.dll
  • NHibernate.dll

I also decided to store the ActiveRecord configuration information in App.Config (there are several configuration methods mentioned in the documentation). My App.config looked like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="activerecord" type="Castle.ActiveRecord.Framework.Config.ActiveRecordSectionHandler, Castle.ActiveRecord" />
  </configSections>
  <activerecord>
    <config>
      <add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
      <add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2005Dialect" />
      <add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
      <add key="hibernate.connection.connection_string" value="Data Source=127.0.0.1\SQLEXPRESS;Initial Catalog=SubSonicWorkshop;Integrated Security=True" />
    </config>
  </activerecord>
</configuration>

The next step was to create my entities, State and Subject:

[ActiveRecord]
public class State : ActiveRecordBase<State> {
  [PrimaryKey(PrimaryKeyType.GuidComb)]
  public Guid StateId { get; set; }
  
  [Property]
  public String Name { get; set; }
}

[ActiveRecord]
public class Supplier : ActiveRecordBase<Supplier> {
  [PrimaryKey(PrimaryKeyType.GuidComb)]
  public Guid SupplierId { get; set; }
  
  [Property]
  public String Name { get; set; }

  [HasAndBelongsToMany(
    typeof(State), RelationType.Bag,
    Table="Supplier_StatesServiced", ColumnKey="SupplierId", ColumnRef="StateId",
    Lazy=true)
  ]
  public IList<State> StatesServiced { get; set; }
}

ActiveRecord uses attributes to specify the mapping between entities and the database. This saves some of the work I went through producing mapping files for the NHibernate example, although as ActiveRecord is built on NHibernate, I am really just specifying the same information in a different form and letting ActiveRecord fill in the blanks.

I just needed to specify a [PrimaryKey] for each entity, add an [ActiveRecord] attribute on the class and a [Property] attribute on persistent properties, and then map the Supplier.StatesServicedcollection to the many-to-many relationship in the database using [HasAndBelongsToMany]. Besides the attributes, the entities need to inherit from ActiveRecordBase<T>, which gives the entity all the ActiveRecord-smarts, but also ties it to this persistence mechanism.

Populating the database

As per my previous posts, I'll use a test fixture to run the remainder of the code. Before we start ActiveRecording, we need to initialise ActiveRecord so it can load up our entity mappings. I did this via a static constructor in the fixture. By calling ActiveRecordStarter.Initialize() without arguments, ActiveRecord will examine the current configuration (we used App.config for this earlier) and assembly to load the appropriate mappings. I assume this is synonomous with the NHibernate SessionFactory initialisation.

[TestFixture]
public class CastleFixture {
  static CastleFixture() {
    ActiveRecordStarter.Initialize();
  }
  ...

We are now ready to populate the database. The method to create a single Supplier is really nice using ActiveRecord:

private static void createSupplier(String name, String[] statesServiced) {
  Supplier supplier = new Supplier();
  supplier.Name = name;
  supplier.StatesServiced = State.FindAll(Expression.In("Name", statesServiced));
  supplier.Create();
}

As usual, we'll run the code below to populate the database with our test data:

createSupplier("Dave^2 Quality Tea", new string[] { "NSW", "VIC" });
createSupplier("ORMs'R'Us", new string[] { "NSW" });
createSupplier("Lousy Example", new string[] { "TAS", "VIC" });
createSupplier("Bridge Sellers", new string[] { "QLD" });

Querying the data

As ActiveRecord is built on NHibernate, you can use most (all?) of the standard NHibernate features for querying your entities, such as HQL (Hibernate Query Language). In addition to that power, ActiveRecord provides a simpler query layer on top of NHibernate via the ActiveRecordBase<State> base class your entities use.

Here's the two simple queries I've been using in the previous posts, first getting all suppliers and then suppliers that have an "s" in their name:

[Test]
public void Should_be_able_to_get_all_suppliers() {
  IList<Supplier> suppliers = Supplier.FindAll();
  Assert.That(suppliers.Count, Is.EqualTo(4));
}

[Test]
public void Should_be_able_to_get_all_suppliers_with_s_in_their_name() {
  IList<Supplier> suppliers = 
    Supplier.FindAll(Expression.Like("Name", "%s%"));
  Assert.That(suppliers.Count, Is.EqualTo(3));
}

And here's the code to get data over the supplier-state relationship, retrieving all suppliers that service NSW:

[Test]
public void Should_be_able_get_all_suppliers_that_service_NSW() {
  IList<Supplier> suppliers = Supplier.FindAll(
    DetachedCriteria.For<Supplier>()
      .CreateCriteria("StatesServiced")
        .Add(Expression.Eq("Name", "NSW"))
    );
  Assert.That(suppliers.Count, Is.EqualTo(2));
}

To be honest I had trouble finding good examples on querying using ActiveRecord in the documentation. I ended up reproducing the NHibernate query. I'm not sure if there is a neater way of doing this -- it wouldn't surprise me if I've missed something obvious here. Still the query works, and I think that, for the first two queries in particular, you aren't going to find a simpler, more concise or easier to understand syntax.

Vague semblance of a conclusion

There is some great information around about configuring ActiveRecord, and it was trivially easy to setup. The only real downside I found during this simple exercise was finding ActiveRecord-specific documentation on querying. I guess the required approach is to use the basic Find/FindAll methods where possible and drop back into NHibernate queries whenever you need more power.

Another consideration when using Castle ActiveRecord is the underlying design pattern itself. If you can't or won't use the ActiveRecord design pattern (for example, want to keep entities and persistence logic seperate), then it isn't going to help you much.

And finally, Castle ActiveRecord also integrates with Monorail, which may be a plus for you if you are developing MVC web applications.

Thursday, 3 January 2008

Messing around with various ORMs

I recently had a quick muck around with a few .NET ORM tools. I took a basic, contrived scenario and tried to implement the same operations using the tools. Here is a quick index:

The examples all go through same steps: the basic configuration required to get going, inserting a couple of records, and then getting some data back out with some simple queries, including traversing a many-to-many relationship.

8 Jan 2008: Quick clarification -- this series is not intended as a review of these tools. It is simply a quick guide to configuring and performing some very basic operations with them. Because all the posts use a (very simple) common scenario, you may be able to draw some basic conclusions about the tools, but in the end you'll probably have to evaluate them for yourself with respect to your own requirements. In which case these posts may help you get started :)

Messing around with ADO.NET Entity Framework Beta 3

This post is part of a small series on .NET ORM tools. You can find the rest of them here.

While I was checking out a number of .NET ORM tools, I thought I'd work through the exercise using the ORM-related bits from the ADO.NET Entity Framework Beta 3 and the Entity Designer CTP2.

Scene refresher

I have a table of suppliers, and a table of states (or provinces, territories, prefectures etc.). Both suppliers and states have names, which are stored as strings/varchars, and IDs, which are stored as Guids/uniqueidentifiers. Each supplier can service many states. So we have a simple many-to-many relationship between the two main entities. It looks a bit like this:

I am using Aussie states for my tests, so I have populated the State table with the following names: NSW, VIC, QLD, TAS, SA, WA, ACT, NT.

Setting up Entity Framework

I created a new C# class library project, then added an ADO.NET Entity Data Model file (.edmx) as a project item, which I named WorkshopModel.edmx. Adding the project item runs a wizard that lets you choose the connection, and then select which database items to include in the model (including tables, views and SPs):

Once the wizard completes the model is opened in the designer. Note the recognition of the many-to-many relationship between suppliers and states. I edited to default association name from Supplier_StatesServiced to StatesServiced to make it a bit easier to read.

The designer provides access to loads of properties for the model, so it is possible that some of the code I am going to write further on could be simplified by tweaking the model. At this stage it feels very much like a WYSIWYG way of generating an NHibernate-style mapping file and accompanying entity classes. The designer generates a WorkshopData.Designer.cs file from my WorkshopData.edmx, which includes definitions of the Entity Framework-based classes.

Populating the database

As per my previous posts, I'll use a test fixture to run the remainder of the code. Here is the method used to create a supplier and map the states it services:

private static void createSupplier(String name, String[] statesServiced) {
  using (WorkshopEntities entityModel = new WorkshopEntities()) {
    Supplier supplier = Supplier.CreateSupplier(Guid.NewGuid(), name);
    foreach (String stateName in statesServiced) {
      supplier.State.Add(entityModel.State.Where(s => s.Name == stateName).First());
    }
    entityModel.SaveChanges();
  } 
}

The WorkshopEntities class gives us access to the relevant Entity Framework bits (it derives from System.Data.Objects.ObjectContext). The designer has generated a static Supplier.CreateSupplier(...) method, but I couldn't find a nice way of adding all the relevant states at once. I would have loved to do something like this:

List<State> states = (from state in entityModel.State
            where statesServiced.Contains(state.Name)
            select state).ToList();
states.ForEach(state => supplier.State.Add(state));

But this gave me an exception:

EntityFrameworkWorkshop.EntityFrameworkFixture.DatabaseSetup : System.NotSupportedException : The 'Boolean Contains[String](System.Collections.Generic.IEnumerable`1[System.String], System.String)' method is not recognized by LINQ to Entities, and cannot be translated into a store expression.

The Entity Framework (as of this release) cannot map the Contains method to Entity SQL. The similar LINQ to SQL query works fine. The difference is that the LINQ to SQL provider is mapping direct to TSQL, whereas the LINQ to Entities provider is mapping to Entity SQL (I think, please correct me if I'm wrong), which needs to work over a variety of sources (not just relational databases). I'm assuming it's tougher to implement something that works over all sources than simply targeting TSQL, but maybe this is just because we aren't in RTM yet.

I had a similar problem when I wanted to write entityModel.State.Where(s => s.Name == stateName).Single(), where I was told that it wouldn't map Single(), but that I might like to try First() instead. Which I did, and it all worked fine. There are a few more comments about this kind of thing here, as well as a list of supported and unsupported methods on MSDN.

Still, at least we have a nice recognition of the relationship between suppliers and states, which was a big drawback with the LINQ to SQL example. We'll then run the code below to populate the database with our test data:

createSupplier("Dave^2 Quality Tea", new string[] { "NSW", "VIC" });
createSupplier("ORMs'R'Us", new string[] { "NSW" });
createSupplier("Lousy Example", new string[] { "TAS", "VIC" });
createSupplier("Bridge Sellers", new string[] { "QLD" });

Querying the data

I'm going to favour using LINQ to Entities for querying in these examples, rather than Entity SQL. Similarly to NHibernate, which has HQL (Hibernate Query Language), Entity Framework can use a SQL-like language to query the domain objects. This gives both tools a lot of query power, at the cost of embedding logic in strings that aren't checked by the compiler and that generally won't work with refactoring tools. I used the ICriteria approach for strongly-typed queries in the NHibernate example, so I'll use LINQ to Entities for this one.

I'll quickly run through the first two simple queries I've been using in the previous posts, first getting all suppliers and then suppliers that have an "s" in their name:

[Test]
public void Should_be_able_to_get_all_suppliers() {
  using (WorkshopEntities entityModel = new WorkshopEntities()) {
    var suppliers = from supplier in entityModel.Supplier select supplier;
    Assert.That(suppliers.Count(), Is.EqualTo(4));
  }
}
[Test]
public void Should_be_able_to_get_all_suppliers_with_s_in_their_name() {
  using (WorkshopEntities entityModel = new WorkshopEntities())   {
    var suppliers = from supplier in entityModel.Supplier
            where supplier.Name.ToLower().Contains("s")
            select supplier;
    Assert.That(suppliers.Count(), Is.EqualTo(3));
  }
}

And here's the code to get data over the supplier-state relationship, retrieving all suppliers that service NSW:

[Test]
public void Should_be_able_get_all_suppliers_that_service_NSW() {
  using (WorkshopEntities entityModel = new WorkshopEntities())   {
    var suppliers = from supplier in entityModel.Supplier
            where supplier.State.Any(state => state.Name == "NSW")
            select supplier;
    Assert.That(suppliers.Count(), Is.EqualTo(2));
  }
}

This is much nicer than the LINQ to SQL version, which required explicitly joining over the relationship:

var suppliers = from supplier in db.Suppliers
        join servicedState in db.Supplier_StatesServiceds 
          on supplier.SupplierId 
          equals servicedState.SupplierId
        where servicedState.State.Name == "NSW"
        select supplier;

Vague semblance of a conclusion

We've only really looked at the ORM side of the Entity Framework in this example, and it definitely seems very capable in this regard (at least for this simple example), but as noted by David Laribee, ORM is a very small part of the Entity Framework. It's main potential is in querying across a model that incorporates different data sources and services (say, different databases, XML sources etc), which is definitely an exciting aim.

The only real issue I had using the tool were the unmapped methods, but this was easy to work around. I think the real test of the tool will be how much you can get into the Entity Data Model and how easy it is to work with. Earlier releases faced some criticisms regarding persistance ignorance and the fact you can't use POCOs for entities, but I believe some of the issues are being addressed (thanks to Tom for the link) by the ADO.NET team based on the feedback they have received.

Friday, 21 December 2007

Messing around with LinqToSql

This post is part of a small series on .NET ORM tools. You can find the rest of them here.

As part of my continuing efforts to fragrantly misuse a number of .NET ORM tools, here is my effort with LinqToSql. The usual proviso applies: all of this is really quick and hacky, as it is just to get a little familiarity with the tool rather than to uncover any "best practices" or similar.

Scene refresher

I have a table of suppliers, and a table of states (or provinces, territories, prefectures etc.). Both suppliers and states have names, which are stored as strings/varchars, and IDs, which are stored as Guids/uniqueidentifiers. Each supplier can service many states. So we have a simple many-to-many relationship between the two main entities. It looks a bit like this:

I am using Aussie states for my tests, so I have populated the State table with the following names: NSW, VIC, QLD, TAS, SA, WA, ACT, NT.

Setting up LinqToSql

I created a new C# class library project, then added a LinqToSql Classes project item, which I named WorkshopDb.dbml. In true Microsoft style, you simply drag and drop the tables from the database onto the designer, which generates the necessary classes for you:

This adds an app.config file to the project, containing the relevant connection string. We are now ready to go!

Populating the database

As per my previous posts, I'll a test fixture to run the remainder of the code. After cleaning out my little database again, I'll add a method to encapsulate the process of creating a supplier and mapping the states it services:

private static void createSupplier(String name, String[] statesServiced) {
  WorkshopDbDataContext db = new WorkshopDbDataContext();

  Supplier supplier = new Supplier();
  supplier.SupplierId = Guid.NewGuid();
  supplier.Name = name;

  List<State> states = (
        from state in db.States
        where statesServiced.Contains(state.Name)
        select state
      ).ToList();

  states.ForEach(
    state => supplier.Supplier_StatesServiceds.Add(
      new Supplier_StatesServiced() {
        SupplierId = supplier.SupplierId,
        StateId = state.StateId
      }
    ));
    
  db.Suppliers.InsertOnSubmit(supplier);
  db.SubmitChanges();
}

As with SubSonic, LinqToSql does not automatically let me traverse the many-to-many relationship, but the new ForEach method makes it pretty easy to map each state to the supplier.Supplier_StatesServiceds collection (man, I really should have aliased that mapping table first).

We can now use that method to add the following test data:

createSupplier("Dave^2 Quality Tea", new string[] { "NSW", "VIC" });
createSupplier("ORMs'R'Us", new string[] { "NSW" });
createSupplier("Lousy Example", new string[] { "TAS", "VIC" });
createSupplier("Bridge Sellers", new string[] { "QLD" });

Querying the data

Let's run through the usual tests. First, getting a list of all suppliers.

[Test]
public void Should_be_able_to_get_all_suppliers() {
  WorkshopDbDataContext db = new WorkshopDbDataContext();
  var suppliers = from supplier in db.Suppliers select supplier;
  Assert.That(suppliers.Count(), Is.EqualTo(4));
}

So far so good. Now let's get all suppliers with an "s" in their name.

[Test]
public void Should_be_able_to_get_all_suppliers_with_s_in_their_name() {
  WorkshopDbDataContext db = new WorkshopDbDataContext();
  var suppliers = from supplier in db.Suppliers
          where supplier.Name.ToLower().Contains("s")
          select supplier;
  Assert.That(suppliers.Count(), Is.EqualTo(3));
}

And finally, let's navigate over the supplier-state relationship to get all suppliers that service NSW:

[Test]
public void Should_be_able_get_all_suppliers_that_service_NSW() {
  WorkshopDbDataContext db = new WorkshopDbDataContext();
  var suppliers = from supplier in db.Suppliers
          join servicedState in db.Supplier_StatesServiceds 
            on supplier.SupplierId 
            equals servicedState.SupplierId
          where servicedState.State.Name == "NSW"
          select supplier;
  Assert.That(suppliers.Count(), Is.EqualTo(2));
}

Pretty straight forward. This actually generates very similar SQL to the NHibernate example, but because I never actually get a list from the suppliers expression, the suppliers.Count() call actually uses SELECT Count(*) ... (I believe you can do similar queries in both NHibernate and SubSonic). The following is roughly what is executed via sp_executesql:

SELECT COUNT(*)
FROM [dbo].[Supplier]
INNER JOIN [dbo].[Supplier_StatesServiced] ON [Supplier].[SupplierId] = [Supplier_StatesServiced].[SupplierId]
INNER JOIN [dbo].[State] ON [State].[StateId] = [Supplier_StatesServiced].[StateId]
WHERE [State].[Name] = @p0

Vague semblance of a conclusion

LinqToSql was extremely easy to use, especially in the initial configuration department. Like NHibernate, the query syntax takes a bit of getting used to, but it is something that becomes familiar fairly quickly.

I should point out that both SubSonic and NHibernate currently target the .NET 2.0 world, so the "Language INtegrated Query" part of LinqToSql was always going to give LinqToSql a bit of an expressiveness advantage. If you are a big fan of LINQ queries, they may be coming to an ORM tool near you in the not-too-distant future now that .NET 3.5 has been released. That said, I still quite like how the query criteria works in the NHibernate example.

I also noticed that NHibernate was more domain model (i.e. classes) focused, whereas the LinqToSql query for retrieving all the suppliers that service NSW was more data-schema focussed (using the JOIN construct rather than have a working knowledge of the relationship). This isn't meant as praise or criticism of either, just a difference in the approaches. As a quick side note, I believe the ADO.NET Entity Framework is meant to have more advanced support for many-to-many relationships.

So far I've actually felt SubSonic was the most difficult to use for this particular scenario, but this is largely a result of the contrived example I used. I have used SubSonic a few times and in general it is exceptionally straight forward to get working.

As I was mainly looking into how each tool tackled this particular scenario, I have not gone into the different architectural approaches of the tools (ActiveRecord vs. DataMapper, implications for testability and persistence ignorance etc.). It's definitely worth looking into this side of things if you are unfamiliar with the tools. Ian Cooper has a great post on some of these issues as applied to LinqToSql.

That's it for now. Good luck on your ORM travels!

Messing around with NHibernate

This post is part of a small series on .NET ORM tools. You can find the rest of them here.

After messing around with SubSonic, I thought I'd run through the same scenario with NHibernate. A quick disclaimer: both tools a very different, so comparing them is a bit like comparing apples and oranges. As an example, a large part of SubSonic is the generation of DAL classes. There are ways of generating relevant NHibernate artifacts, but they aren't really an integral part of the tool.

Still, I'm not going to let a simple thing like facts get in the way of proceeding. I was interested to see how to perform the same basic scenario as last time around using NHibernate. And as per last time, all of this is really quick and hacky, as it is just to get a little familiarity with the tool rather than to uncover any "best practices" or similar. So here goes...

Scene refresher

I have a table of suppliers, and a table of states (or provinces, territories, prefectures etc.). Both suppliers and states have names, which are stored as strings/varchars, and IDs, which are stored as Guids/uniqueidentifiers. Each supplier can service many states. So we have a simple many-to-many relationship between the two main entities. It looks a bit like this:

I am using Aussie states for my tests, so I have populated the State table with the following names: NSW, VIC, QLD, TAS, SA, WA, ACT, NT.

Setting up NHibernate

I created a new C# class library project and added a reference to NHibernate. I chucked in an app.config for NHibernate's benefit that ended up like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="nhibernate"
       type="System.Configuration.NameValueSectionHandler, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
    />
  </configSections>
  <nhibernate>
    <add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
    <add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2005Dialect" />
    <add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
    <add key="hibernate.connection.connection_string" value="Data Source=127.0.0.1\SQLEXPRESS;Initial Catalog=SubSonicWorkshop;Integrated Security=True" />
  </nhibernate>
</configuration>

Rather than using any NHibernate auto-mapping or code generation, I manually created the classes I wanted. I am using the automatic property accessors in C# 3.0, so if you're still using 2.0 you'll need to manually add a backing store for these.

/* State.cs */
public class State {
  public Guid StateId { get; set; }
  public String Name { get; set; }
}
/* Supplier.cs */
public class Supplier {
  public Guid SupplierId { get; set; }
  public String Name { get; set; }
  public IList<State> StatesServiced { get; set; }
}

I then need to tell NHibernate how I want to map between these classes and my relational data. You can do this by creating Hibernate Mapping files (.hbm.xml), and setting them to be included as embedded resources in the compiled DLL. Again, I did this manually, but you specify use attributes on your classes to do this auto-magically, or generate the classes, database, and/or mapping files using a variety of tools.

First let's look at the mapping for states (State.hbm.xml):

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
                   assembly="NHibernateWorkshop.Tests" 
                   namespace="NHibernateWorkshop.Tests">
  <class name="State" table="State" lazy="false">
    <id name="StateId" type="guid">
      <generator class="guid" />
    </id>
    <property name="Name" type="String" />
  </class>
</hibernate-mapping>

Here I am telling NHibernate that a State has a StateId, which is the primary key. I am also telling NHibernate that it can generate this ID as a new Guid. I also let it know it can persist the Name property as a String. By default NHibernate will match the property name with the column name, but you can also specify that a property matches to a different column name if you like.

Now for the more interesting entity mapping, Supplier.hbm.xml:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="NHibernateWorkshop.Tests"
                   namespace="NHibernateWorkshop.Tests">
  <class name="Supplier" table="Supplier" lazy="false">
    <id name="SupplierId" type="guid">
      <generator class="guid" />
    </id>
    <property name="Name" type="String" />
    <bag name="StatesServiced" table="Supplier_StatesServiced">
      <key column="SupplierId" />
      <many-to-many column="StateId" class="State" />
    </bag>
  </class>
</hibernate-mapping>

This is very similar to the last mapping, with the exception of the <bag> property. This tells NHibernate that I have a many-to-many relationship between State and Supplier, and that it can navigate this relationship using the Supplier_StatesServiced table and the SupplierId and StateId keys.

Creating a test fixture for messing around

As I mentioned last time, I like working in test fixtures, so I created a new test fixture to run the remainder of the code in this post. Before I start using NHibernate within the fixture, I want to get access to the NHibernate ISession. I guess you could think of ISession as a conversation between NHibernate and the database. I'll do this by exposing a ISessionFactory property (note, there are optimal ways of doing this... this ain't it):

protected static readonly ISessionFactory SessionFactory = initialSessionFactory();
private static ISessionFactory initialSessionFactory() {
  Configuration config = new Configuration();
  config.AddAssembly("NHibernateWorkshop.Tests");
  return config.BuildSessionFactory();
}

I am going to use this property to create sessions as required. The AddAssembly(...) call gets NHibernate to load in all the .hbm.xml mapping files we created earlier, so the sessions we create know how to persist our entities.

Populating the database

Now we can get to work populating our database (I cleaned it out from last time). We are now on par with the SubSonic example. The steps and method signatures are going to be very similar from here on in. So like last time, I'll write a method to encapsulate the process of creating a supplier and mapping the states it services:

private static void createSupplier(String name, String[] statesServiced) {
  using (ISession session = SessionFactory.OpenSession())
  {
    Supplier supplier = new Supplier();
    supplier.Name = name;
    IList<State> states = session
      .CreateCriteria(typeof (State))
      .Add(
        Expression.In("Name", statesServiced)
      )
      .List<State>();
    supplier.StatesServiced = states;
    session.SaveOrUpdate(supplier);
    session.Flush();
    session.Close();
  }
}

Wow. To me all that additional setup now starts to seem worth it. I create a normal object and set the name property. I then create a criteria object that is going to query states, and add a restriction that the state's name must be in the array of statesServiced we passed in. I then assign the results to the supplier object, and ask the NHibernate session to SaveOrUpdate the supplier. (SaveOrUpdate means NHibernate will automatically determine whether it needs to INSERT or UPDATE the relevant database record.) As ISession represents a chat with a database, the whole thing is wrapping in a using (...) { } to ensure any resources used are cleaned up nicely.

I then used the following code to insert the same data as last time:

createSupplier("Dave^2 Quality Tea", new string[] { "NSW", "VIC" });
createSupplier("ORMs'R'Us", new string[] { "NSW" });
createSupplier("Lousy Example", new string[] { "TAS", "VIC" });
createSupplier("Bridge Sellers", new string[] { "QLD" });

Querying the data

Let's get a list of all the suppliers:

[Test]
public void Should_be_able_to_get_all_suppliers() {
  using (ISession session = SessionFactory.OpenSession()) {
    IList<Supplier> suppliers = session.CreateCriteria(typeof (Supplier)).List<Supplier>();
    Assert.That(suppliers.Count, Is.EqualTo(4));
  }
}

That's pretty much on a par with the SubSonic equivalent. The test passes. Now let's get all the suppliers with an "s" in their name:

[Test]
public void Should_be_able_to_get_all_suppliers_with_s_in_their_name() {
  using (ISession session = SessionFactory.OpenSession()) {
    IList<Supplier> suppliers = session
      .CreateCriteria(typeof (Supplier))
      .Add(Expression.Like("Name", "%s%"))
      .List<Supplier>();
    Assert.That(suppliers.Count, Is.EqualTo(3));
  }
}

Again, pretty simple, and very similar to the SubSonic version. Now to the tricky example. We want to navigate over the supplier-state relationship and get all the suppliers that service NSW. This one wasn't pretty in SubSonic.

[Test]
public void Should_be_able_get_all_suppliers_that_service_NSW() {
  using (ISession session = SessionFactory.OpenSession()) {
    IList<Supplier> suppliers = session
      .CreateCriteria(typeof (Supplier))
      .CreateCriteria("StatesServiced")
        .Add(Expression.Eq("Name", "NSW"))
      .List<Supplier>();
    Assert.That(suppliers.Count, Is.EqualTo(2));
  }
}

Again, wow. That was too easy. First we create a criteria that is going to return Supplier data. Then we want a sub-criteria that is going to use the StatesServiced property of the Supplier entity (not the table -- we are strictly dealing in domain objects here). We then say we only want the StatesServiced collection to include NSW. So what SQL ends up hitting the database?

SELECT {fields for supplier and state} 
FROM Supplier 
  INNER JOIN Supplier_StatesServiced ON
    Supplier.SupplierId=Supplier_StatesServiced.SupplierId 
  INNER JOIN State ON Supplier_StatesServiced.StateId=State.StateId 
WHERE State.Name = @p0

This is the query executed via a call to sp_executesql on SQL Server (slightly modified to better communicate the point, but the actual generated query is still very neat), with "NSW" passed as @p0.

This was very different to the experience with SubSonic, which I couldn't get to sensibly navigate over the many-to-many relationship.

Vague semblance of a conclusion

Ignoring the initial setup and configuration (as this can all be generated, but to be honest it was all fairly quick), I really enjoyed working with NHibernate. While the querying looked a little daunting to me at first glance, after about 3 seconds I found it very intuitive. Sometimes when I was working with SubSonic I found myself scratching my head as to how to get back specific information. Not so with NHibernate, as the query options I needed* were all fairly discoverable, and I never felt like I was going to have to fight the tool to get stuff out.

Again, there are vast differences between the SubSonic and NHibernate approaches, and there a probably situations to which one is better suited than the other. Rob Conery has a good post about the strengths and weaknesses of both tools, as well as LinqToSql.

Here are a couple of chapters from the official documentation that I used to get NHibernate going:

* Luckily I didn't need Projections or similar. That may have started to get a bit hairier.

Thursday, 20 December 2007

Messing around with SubSonic

This post is part of a small series on .NET ORM tools. You can find the rest of them here.

I recently heard a complaint about SubSonic queries, especially with regards to joining between tables. After looking at the forums, which basically recommended replacing complex queries or joins with SPs, I decided to have a quick play around myself. Note that all of this is really quick and hacky, as it is just to get a little familiarity with the tool rather than to uncover any "best practices" or similar. If you know better ways of doing the stuff below then you are more than welcome to leave a comment. :-)

Update 11 Jan 2008: Rob has announced that development of SubSonic version 2.1 is underway. 2.1 will have an updated query tool, so chances are the queries attempted in this post will be easier in the new version. This post relates to version 2.0.

Setting the scene

I have decided to use a <sarcasm>very realistic and common scenario</sarcasm> for my tests. I have a table of suppliers, and a table of states (or provinces, territories, prefectures etc.). Both suppliers and states have names, which are stored as strings/varchars, and IDs, which are stored as Guids/uniqueidentifiers. Each supplier can service many states. So we have a simple many-to-many relationship between the two main entities. It looks a bit like this:

I am using Aussie states for my tests, so I have populated the State table with the following names: NSW, VIC, QLD, TAS, SA, WA, ACT, NT (yes, my state table holds territories). This is all sitting in a little SQL Express database that I called SubSonicWorkshop.

Setting up SubSonic

After creating a new C# class library project and adding a reference to SubSonic, I add an app.config file that looks like this*:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="SubSonicService" type="SubSonic.SubSonicSection, SubSonic" requirePermission="false"/>
</configSections>
<connectionStrings>
<clear/>
<add name="SubSonicWorkshop" connectionString="Data Source=127.0.0.1\SQLEXPRESS;Initial Catalog=SubSonicWorkshop;Integrated Security=True" />
</connectionStrings>
<SubSonicService defaultProvider="SubSonicWorkshop">
<providers>
  <clear/>
  <add name="SubSonicWorkshop" type="SubSonic.SqlDataProvider, SubSonic"
    connectionStringName="SubSonicWorkshop"  generatedNamespace="SubSonicWorkshop.DataAccess" />
</providers>
</SubSonicService>
</configuration>

I then created a Generated folder within the solution and ran SubCommander to populate it:

C:\Program Files\SubSonic\SubSonic 2.0.3\SubCommander\sonic.exe generate /out Generated

After getting VS to show all files in the solution, then including all the generated class files, we are ready to go.

Populating the database

I tend to like working in test fixtures, so I created a test fixture class and use my test runner to run the following snippets of code. Firstly, let's write a method to encapsulate the process of creating a supplier and mapping the states it services:

private static void createSupplier(String name, String[] statesServiced) {
 Supplier supplier = new Supplier();
 supplier.SupplierId = Guid.NewGuid();
 supplier.Name = name;
 supplier.Save();

 if (statesServiced.Length == 0) return;

 Query stateQuery = State.CreateQuery().IN("Name", statesServiced);
 StateCollection states = new StateCollection();
 states.LoadAndCloseReader(stateQuery.ExecuteReader());

 //Not sure why this doesn't work (raises exception):
 //Supplier.SaveStateMap(supplier.SupplierId, states);
 //Using this instead:
 foreach (State state in states) {
   SupplierStatesServiced.Insert(supplier.SupplierId, state.StateId);
 }
}

This code creates and saves a supplier with the given name. It then retrieves a collection of states that match the state names passed in via the array, and maps these to the newly saved supplied. For some reason I couldn't get the Supplier.SaveStateMap(...) call to work, so I did the mapping using a loop. Seeing as I don't have SVN access through the firewall here I haven't delved into the SubSonic source to see where things are going wrong. I then made the following calls to add some test data:

createSupplier("Dave^2 Quality Tea", new string[] { "NSW", "VIC" });
createSupplier("ORMs'R'Us", new string[] { "NSW" });
createSupplier("Lousy Example", new string[] { "TAS", "VIC" });
createSupplier("Bridge Sellers", new string[] { "QLD" });

Querying the data

First up I wanted to see if I could load all my suppliers:

[Test]
public void Should_be_able_to_get_all_suppliers() {
 SupplierCollection suppliers = new SupplierCollection().Load();
 Assert.That(suppliers.Count, Is.EqualTo(4));
}

Yep, no problems there. How about getting all the suppliers that have an "s" in their name?

[Test]
public void Should_be_able_to_get_all_suppliers_with_s_in_their_name() {
 SupplierCollection suppliers = new SupplierCollection();
 suppliers.Where(Supplier.Columns.Name, Comparison.Like, "%s%");
 suppliers.Load();
 Assert.That(suppliers.Count, Is.EqualTo(3));
}

No problems there either. Now let's get a bit uglier. I want to navigate over the supplier-state relationship and get all suppliers that service NSW. I think this may be one of the situations mentioned on the SubSonic forums where you would probably want to use an SP to cut down the amount of chatting with the DB:

[Test]
public void Should_be_able_to_get_all_suppliers_that_service_NSW() {
 State nsw = new State(State.Columns.Name, "NSW");

 SupplierStatesServicedCollection statesServicedMap = new SupplierStatesServicedCollection();
 statesServicedMap.Where(State.Columns.StateId, nsw.StateId);
 statesServicedMap.Load();

 SupplierCollection nswSuppliers = new SupplierCollection();
 foreach (SupplierStatesServiced supplierService in statesServicedMap) {
   nswSuppliers.Add(supplierService.Supplier);
 }
 Assert.That(nswSuppliers.Count, Is.EqualTo(2));
}

The code above first gets the state we are interested in (NSW), and then gets all the mappings that feature this state. It then loops through all the mappings and adds the supplier the the SupplierCollection. This worked, but I'd hate to use that with more than a handful of records.

I think in the last situation you'd probably want to use an SP (or direct SQL). Because SubSonic generates partial classes, you could also add a method to State, StateCollection or StateController like FetchByServicedState(String stateName) to do this in a reusable manner.

That's it for now. I'm going to have a quick play with doing this in NHibernate and LinqToSql.

* I know I prevoiusly committed to giving colourful code samples, but I ran in to a few hurdles with the tool and am sticking to plain, boring code samples for now.

Wednesday, 14 November 2007

Locating NHibernate Mapping Files

I have an assembly full of data objects (say, MyGreatApp.Objects.dll), and an assembly that manages data access (say, MyGreatApp.DataAccess.dll). As the data access DLL is handling persistence, it should have the embedded NHibernate mapping files (*.hbm.xml). I tried to configure a session factory from MyGreatApp.DataAccess.dll like this:

Configuration config = new Configuration();
config.AddClass(typeof(MyGreatApp.Objects.Widget));
SessionFactory = config.BuildSessionFactory();

I thought this would search the current assembly for the Widget.hbm.xml file, and possible the assembly containing the referenced type as well. I was quickly proved wrong as it threw NHibernate.MappingException: Resource not found. NHibernate is only looking for the Widget mapping file in the same place as the type itself, which is MyGreatApp.Objects.dll. Instead we just need to explicitly add the assembly that contains the embedded mapping files:

Configuration config = new Configuration();
config.AddAssembly("MyGreatApp.DataAccess");
SessionFactory = config.BuildSessionFactory();

And this works great! I noticed Jim Holmes is years ahead of me here, but I didn't have much Google-luck with my initial choice of keywords and so thought I'd post my experience.

Thursday, 1 November 2007

Getting SubSonic talking to Oracle

I wasn't sure how well SubSonic would play with Oracle, but it turns out that it was very easy to get the basics working. First, I setup a data access class and the SubSonic basics like VS external tools etc.

Instead of the configuration suggested in the above link, my App.config looked like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="SubSonicService" type="SubSonic.SubSonicSection, SubSonic" requirePermission="false"/>
  </configSections>
  <connectionStrings>
    <clear/>
    <add name="MyAppsConnectionString" providerName="Oracle.DataAccess"
      connectionString="Data Source=MyOracleServer;User Id=MyUserId;Password=MyPassword;Integrated Security=no;" />
  </connectionStrings>
  <SubSonicService defaultProvider="MyApp">
    <providers>
      <clear/>
      <add name="MyApp" type="SubSonic.OracleDataProvider, SubSonic"
        connectionStringName="MyAppsConnectionString"  generatedNamespace="MyApp.DataAccess" />
    </providers>
  </SubSonicService>
</configuration>

The emphasised bits will vary for you obviously. If you need connection string help check ConnectionStrings.com for your Oracle provider. I am using Oracle Data Provider for .NET, so your providerName may vary if you are using a different one.

It was then just a matter of running Sonic.exe generate /out Generated via the external tool configured earlier (or manually running it) from the project directory, and out pops your data access layer.

Saturday, 19 May 2007

ScribeSonic: Example of a blog written with SubSonic

Great post pointed out by Rob Connery: ScribeSonic - Getting Loaded on SubSonic - Collection Basics. Covers using SubSonic for a real application.

Wednesday, 18 April 2007

SubSonic 2.0 webcast on sonic.exe command line tool

Rob has a webcast on using the new sonic.exe tool from the command line. This is very nice stuff, and addresses the only hesistations I had about the pre-2.0 release, which was the requirement to use build providers with ASP.NET. I was going to write my own to use SubSonic from within a class library project, but procrastination (well, lack of free time) has paid off :-)

The webcast shows how to setup sonic.exe as an external tool within VS.NET that lets you generate your DAL at single button click. Rob also demonstrates using sonic.exe to version your database schema and data (although it uses SMO, which seems to use a fairly arbitrary ordering for scripting objects and therefore minimises the effectiveness of diff tools. I have not played around with it too much so hopefully I am wrong or the SubSonic team have implemented it in a diff-able way).

Finally, and the news I was hoping for, is the demonstration of running the tool as a pre-build or pre-run action. Combined with using partial classes for any relevant extensions, it now looks like we can have instantly generated, compiler checked database access logic inserted into your domain logic layer or as a new DLL. The last thing I want to look at with SubSonic is potentially generating interfaces, stubs and/or mocks for unit testing without the database itself. I have some time set aside to play with SubSonic this week, and am really looking forward to it.

Sunday, 15 April 2007

Hibernate Best Practices with ASP.NET on CodeProject.com

Billy McCafferty has updated his article on NHibernate Best Practices with ASP.NET. This covers a range of topics regarding ASP.NET development with NHibernate, including practices for application architecture and unit testing.

Wednesday, 28 March 2007

SubSonic - instant data access layer

SubSonic (aka ActionPack) is an incredibly nice tool for generating a data access layer direct from your database schema, including strongly-typed, ActiveRecord-based access to tables, and stored procedures. There is a nice demonstration of it in action.

Wednesday, 21 March 2007

NHibernate Plugin for Visual Studio 2005

Graphical designer for VS.NET 2005 that generates .hbm.xml files for NHibernate.

Tuesday, 20 March 2007

Linq for Entities: MVP impressions from MVP Summit 2007

Jeremy Miller has a good summary of the general MVP impressions of Linq for Entities after the recent MVP Summit. Everyone seems impressed by the potential of the product, but I was very interested to hear other OR Mappers, specifically NHibernate, being preferred at this stage. Apparently there has been lots of feedback to the developers to make Linq for Entities a bit less invasive (so Plain Old CLR Objects can be Persistance Ignorant and require less configuration).

He also talks about the general feeling amount MVPs that the WebForms model is lacking, and a growing surge of interest in MonoRail. ScottGu is apparently thinking along the same lines. Exciting times. :-)

Saturday, 17 March 2007

Linq for NHibernate

Jeremy Miller has pointed out there is work afoot to use Linq as a front-end for NHibernate. ScottGu mentioned earlier that Linq was designed for this kind of interoperability (point #3 under the heading "Built-in System.Linq Extension Methods" which specifically mentions NHibernate et al). It's nice to see this kind of approach from MS becoming more prevalent.

Wednesday, 13 December 2006

NHibernate: Object persistance for .NET

NHibernate is a .NET port of Hibernate for Java. From the website:

"[NHibernate] handles persisting plain .NET objects to and from an underlying relational database."

NHibernate has close ties to the well known and well documented Hibernate project, so there is lots of information available. This is on the must-try list, as soon as I get a spare second and a half at work.

Other O/R mappers include LLBLGen Pro and WilsonORMapper.