You are currently browsing the category archive for the 'NHibernate' category.

Very often you’re going over a description of some function or new feature and just notice in your mind, “nice feature” without seeing a real application for it. Later, you’re coming with scenario where the trick you’ve read days ago will fit perfectly.

That was the case when I’ve seen earlier in Tuna Toksoz’s weblog a description of “hbm2ddl.auto” property. Few days ago, I’ve put it to work in a way that makes me feel better. By the way, the particular reason that made me happy was that I’ve deleted a lot of repetitive code from our code base.

How you can use hbm2ddl.auto property in unit tests

Our integration tests are run over a real database. For each test we’re re-creating the database, so that each test will be ran in separation and without interfering with results of previous tests. Also, things are a bit complicated since we’re working with few databases at the same time, each with his own schema. Before, each test had to use SchemaExport class that exported the database schema built from NHibernate configuration on the way deleting your old database/schema/data. So, each integration test class had same method to call. Redundant and repetitive. Yes, you can make a base class that will do that, but you have to inherit then all tests from that class.

How it works now: in session configuration (usually in app.config for integration test project) you put:

<property name=”hbm2ddl.auto”>create</property>

… and you’re set. Each time your code will build a new SessionFactory, NHibernate will call:

new SchemaExport(cfg).Create(false, true);

This way, before the SessionFactory will be built, your database will be refreshed with a new schema and tests will run in a clean database.

One line of code instead of tens or hundreds. Isn’t that a good trick?!

 

A word of warning - don’t let this code escape to your production code. It may be dangerous… But, you know that, we’re running with scissors…

RWS2-Big

As always, business requirement went over existing code base to ask for a minor change that wasn’t compatible with our existing infrastructure: all surrogate keys are unique identifiers (Guid) and all infrastructure was built around that. The business people asked to add to an existing domain entity a natural key - integer identity number (auto increment field), to serve as a reference number.

We had two choices:

  • to generate the identity from business code
  • to let database manage it for us.

The second approach it preferable for us because it’s the database’s job to generate the keys.

Out of the box NHibernate doesn’t support such a thing. Answers to my question in NHibernate Users discussion group led to the next solution.

Given the class:

public class Entity
{
    public int Id { get; set; }
    public int Id2 { get; set; }
}

First “Id” is the primary key, the second is the key that we want to map to identity column. To have that done we should do two things:

  • Map “Id2″ property as “generated”
  • Use “database-object” to drop the column generated by NHibernate & create new one, with IDENTITY set on.

The complete mapping:

<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    namespace="NHibernate.Playground"
    assembly="NHibernate.Playground"
    default-lazy="false" xmlns="urn:nhibernate-mapping-2.2">
  <class name="Entity">
    <id name="Id">
      <generator class="increment" />
    </id>
    <property name="Id2" type="int" generated="always" insert="false" />
  </class>
  <database-object>
    <create>
      ALTER TABLE Entity DROP COLUMN Id2
      ALTER TABLE Entity ADD Id2 INT IDENTITY
    </create>
    <drop>
      ALTER TABLE Entity DROP COLUMN Id2
    </drop>
  </database-object>
</hibernate-mapping>

I like the flexibility offered by NHibernate. Even if you don’t have required feature, you can always use naked ADO.NET or raw SQL.

Generally, the goal of integration tests is to verify that different application parts are glued well together and interacts as expected. Thus, they are a bit different thing from unit tests that tends to test how a small, separate part is acting. Below are two tests that I can’t classify to be pure integration tests because they touch a sensible part of application/infrastructure configuration like Windsor’s configuration files and NHibernate’s mappings. These simple tests can save a lot of time at very initial development stage when application bits are changed frequently and later, as a guarantee that you’ve not broken something in a recent refactoring.

Can_resolve_all_services_in_container()

Bill Simser wrote some time ago about the first test to be written when using Castle’s Windsor Container. It’s a real gem that let’s you verify if any of services registered in container can be resolved (have all required dependencies). Here is it, a bit improved for skipping verification for generic types, since, at that moment, we don’t know the generic argument for type to be constructed:

[Test]
public void Can_resolve_all_services_in_container()
{
    var container = new WindsorContainer("container.xml");
    foreach (IHandler handler in container.Kernel.GetAssignableHandlers(typeof(object)))
    {
        if (handler.ComponentModel.Service.IsGenericType)
            continue;

        container.Resolve(handler.ComponentModel.Service);
    }
}

Can_compile_NHibernate_mapping_configuration()

This test was sitting for a long time in our codebase, but I’ve seen it recently in this post of David Larebee. I wrote it in times when writing our first mappings and the only one way to verify if you don’t have any faults was to write one of CRUD operations and run the test. But that’s a long process. Shorter response cycle is always better. Here it is:

[Test]
public void Can_compile_NHibernate_mapping_configuration()
{
    ISessionFactory factory =
        new Configuration()
            .Configure()
            .AddAssembly("MyApp.MyDomainAssembly")
            .BuildSessionFactory();

    Assert.IsNotNull(factory);
}

This test suppose that you have HNibernate configuration in your app.config and tries to register all mappings from given assembly file.