Adjusting NHibernate mapping for tests

As nice as SQLite is for tests it is very sim­ple data­base, and it does not have all the options ‘big’ data­bases pro­vide (for­eign key enforce­ment!). I don’t think there’s much you can do about this issue, but there’s more.

SQLite does not sup­port all the map­pings you can have. I bumped into this issue when work­ing with map­ping sim­i­lar to described in this post. Basi­cally when you try to cre­ate schema from this mapping:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
                   namespace="ConsoleApplication1" 
                   assembly="ConsoleApplication1">
  <class name="Invoice">
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <property name="InvoiceRtfString" type="StringClob">
      <column name ="RtfText" sql-type="nvarchar(MAX)"/>
    </property>
    <property name="ScannedInvoiceJpg" type="BinaryBlob">
      <column name ="JpgData" sql-type="varbinary(max)" />
    </property>
  </class>
</hibernate-mapping>

You’ll get an error:

SQLite error near "MAX": syn­tax error

That’s because SQLite does not know how to han­dle nvarchar(max) or varbinary(max). It has its own types for that – TEXT and BLOB. So you’re either stuck, or have two sets of map­pings – one for tests for SQLite, one for pro­duc­tion, for SQL Server. But wait, there’s third option!

In the pre­vi­ous post, you may have noticed, that in DbTests­Base Init method I call:

new Remapper().Remap(configuration);

Remap­per is my rem­edy for that prob­lem. It’s a sim­ple class that tra­verses the map­ping look­ing for incom­pat­i­bil­i­ties and adjusts it on the fly before cre­at­ing ses­sion fac­tory and schema. This lets you have sin­gle map­ping (be it XML or Flu­entNHiber­nate) while still using SQLite for tests.

The class looks like this:

public class Remapper
{
    private IDictionary<string, String> map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 
    public Remapper()
    {
        map.Add("varbinary(max)", "BLOB");
        map.Add("nvarchar(max)", "TEXT");
    }
 
    public void Remap(Configuration configuration)
    {
        foreach (var classMapping in configuration.ClassMappings)
        {
            this.Remap(classMapping.Table);
        }
    }
 
    private void Remap(Table table)
    {
 
        if (table.Name.Contains("."))
        {
            // found on http://www.nablasoft.com/alkampfer/index.php/2009/07/24/manage-in-memory-nhibernate-test-with-sqlite-and-database-schema/
            // this is a table with schema
            table.Name = table.Name.Replace(".", "_");
        }
 
        foreach (var column in table.ColumnIterator)
        {
            this.Remap(column);
        }
 
    }
 
    private void Remap(Column column)
    {
        if (string.IsNullOrEmpty(column.SqlType))
        {
            return;
        }
 
        string sqlType;
        if (!this.map.TryGetValue(column.SqlType, out sqlType))
        {
            return;
        }
 
        column.SqlType = sqlType;
    }
}

It is very sim­ple and basic, because I cre­ated it for my very spe­cific needs, but with lit­tle effort you could extend it to han­dle more incompatibilities.

Tech­no­rati Tags: ,