Working with NHibernate without default constructors

In the pre­vi­ous post we estab­lished that the usage of default con­struc­tor required by NHiber­nate is the­o­ret­i­cally not required. The fact that NHiber­nate does use them though has to do with tech­ni­cal lim­i­ta­tions of CLR. Turns out in most cases there is a workaround, which is not per­fect but was a fun exper­i­ment to implement.

The code pre­sented here is just an exper­i­ment. It is not of pro­duc­tion qual­ity — it is merely a proof of con­cept so if you use it in pro­duc­tion and the world blows up, don't blame me.

Inter­cep­tor

The place that NHiber­nate lets you plug into to instan­ti­ate enti­ties and com­po­nents as they are pulled from data­base is in NHibernate's IIn­ter­cep­tor (not to be con­fused with Cas­tle Dynam­icProxy IIn­er­cep­tor) inter­face and its instan­ti­ate method. NHiber­nate has also a IOb­jects­Fac­tory inter­face but that one is used to instan­ti­ate every­thing includ­ing NHibernate's own infra­struc­ture (like IUser­Types for exam­ple) and we want to over­ride only acti­va­tion of enti­ties and components.

public class ExtensibleInterceptor : EmptyInterceptor
{
	private readonly INHibernateActivator activator;

	public ISessionFactory SessionFactory { get; set; }

	public ExtensibleInterceptor(INHibernateActivator activator)
	{
		this.activator = activator;
	}

	public override object Instantiate(string clazz, EntityMode entityMode, object id)
	{
		if (entityMode == EntityMode.Poco)
		{
			var type = Type.GetType(clazz);
			if (type != null && activator.CanInstantiate(type))
			{
				var instance = activator.Instantiate(type);
				SessionFactory.GetClassMetadata(clazz).SetIdentifier(instance, id, entityMode);
				return instance;
			}
		}
		return base.Instantiate(clazz, entityMode, id);
	}
}

The code here is straight­for­ward. The INHiber­nate­Ac­ti­va­tor is a cus­tom inter­face that we'll dis­cuss in details below. That's where the actual acti­va­tion hap­pens. We're also using ISes­sion­Fac­tory so that we prop­erly set the id of retrieved instance.

Proxy val­ida­tor

Turns out that is not enough. In the inter­cep­tor we acti­vate objects we fully obtain from the data­base. How­ever big part of NHiber­nate per­for­mance opti­mi­sa­tion is to ensure we don't load more data that we need (a.k.a. lazy load­ing) and to do it trans­par­ently NHiber­nate uses proxies.

For every per­sis­tent type NHiber­nate uses object called proxy val­ida­tor to ensure object meets all the require­ments it has to be able to prop­erly proxy a type and that work is done by IProxyValidator.

Part of the work of proxy val­ida­tor is to check for default con­struc­tor so we need to over­ride that logic to reas­sure NHiber­nate we have things under control.

public class CustomProxyValidator : DynProxyTypeValidator
{
	private const bool iDontCare = true;

	protected override bool HasVisibleDefaultConstructor(Type type)
	{
		return iDontCare;
	}
}

Proxy fac­tory

Now that we told NHiber­nate we can han­dle prox­y­ing types with­out default con­struc­tor it's time to write code that actu­ally does it. That's the task of Prox­y­Fac­tory which uses Cas­tle Dynam­icProxy under the cover

public class CustomProxyFactory : AbstractProxyFactory
{
	protected static readonly IInternalLogger log = LoggerProvider.LoggerFor(typeof (CustomProxyFactory));
	private static readonly DefaultProxyBuilder proxyBuilder = new DefaultProxyBuilder();
	private readonly INHibernateActivator activator;

	public CustomProxyFactory(INHibernateActivator activator)
	{
		this.activator = activator;
	}

	public override INHibernateProxy GetProxy(object id, ISessionImplementor session)
	{
		try
		{
			var proxyType = IsClassProxy
				                ? proxyBuilder.CreateClassProxyType(
				                	PersistentClass,
				                	Interfaces,
				                	ProxyGenerationOptions.Default)
				                : proxyBuilder.CreateInterfaceProxyTypeWithoutTarget(
				                	Interfaces[0],
				                	Interfaces,
				                	ProxyGenerationOptions.Default);

			var proxy = activator.Instantiate(proxyType);

			var initializer = new LazyInitializer(EntityName, PersistentClass, id, GetIdentifierMethod, SetIdentifierMethod,
				                                    ComponentIdType, session);
			SetInterceptors(proxy, initializer);
			initializer._constructed = true;
			return (INHibernateProxy) proxy;
		}
		catch (Exception e)
		{
			log.Error("Creating a proxy instance failed", e);
			throw new HibernateException("Creating a proxy instance failed", e);
		}
	}

	public override object GetFieldInterceptionProxy()
	{
		var proxyGenerationOptions = new ProxyGenerationOptions();
		var interceptor = new LazyFieldInterceptor();
		proxyGenerationOptions.AddMixinInstance(interceptor);
		var proxyType = proxyBuilder.CreateClassProxyType(PersistentClass, Interfaces, proxyGenerationOptions);
		var proxy = activator.Instantiate(proxyType);
		SetInterceptors(proxy, interceptor);
		SetMixin(proxy, interceptor);

		return proxy;
	}

	private void SetInterceptors(object proxy, params IInterceptor[] interceptors)
	{
		var field = proxy.GetType().GetField("__interceptors");
		field.SetValue(proxy, interceptors);
	}

	private void SetMixin(object proxy, LazyFieldInterceptor interceptor)
	{
		var fields = proxy.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
		var mixin = fields.Where(f => f.Name.StartsWith("__mixin")).Single();
		mixin.SetValue(proxy, interceptor);
	}
}

It is pretty stan­dard and not very inter­est­ing. We're again using the INHiber­nate­Ac­ti­va­tor, we've yet to dis­cuss, to cre­ate instances. Also since we're not call­ing any con­struc­tors to do it, we have to set the proxy depen­den­cies that would oth­er­wise by pro­vided via con­struc­tor inline. For that we're using some inter­nal knowl­edge about how Dynam­icProxy lays out its proxy types.

Good news is — we're almost there. Actu­ally we might want to also over­ride NHiber­nate reflec­tion opti­mizer. As its name implies replaces some actions that are per­formed via reflec­tion with faster, com­piled ver­sions. The default one works with assump­tion that default con­struc­tor is avail­able and may fail oth­er­wise but we can dis­able that fea­ture for our sim­ple proof of con­cept application.

Proxy fac­tory factory

There's one more step actu­ally — we need to attach out proxy fac­tory and proxy val­ida­tor to ses­sion fac­tory and we do that via ridicu­lously named IProxyFactoryFactory

public class CustomProxyFactoryFactory : IProxyFactoryFactory
{
	public IProxyFactory BuildProxyFactory()
	{
		return new CustomProxyFactory(new NHibernateActivator());
	}

	public bool IsInstrumented(Type entityClass)
	{
		return true;
	}

	public bool IsProxy(object entity)
	{
		return (entity is INHibernateProxy);
	}

	public IProxyValidator ProxyValidator
	{
		get { return new CustomProxyValidator(); }
	}
}

Putting it all together

Now that we have all these pieces let's see how we put them together (with some help from FluentNHibernate)

var config = Fluently.Configure()
	.Mappings(c => c.FluentMappings.AddFromAssemblyOf<Program>())
	.Database(MsSqlConfiguration.MsSql2008
				.ConnectionString(s => s.Database("NHExperiment").Server(".").TrustedConnection())
				.ProxyFactoryFactory<CustomProxyFactoryFactory>())
	.BuildConfiguration();
var interceptor = new ExtensibleInterceptor(new NHibernateActivator());
config.Interceptor = interceptor;
NHibernate.Cfg.Environment.UseReflectionOptimizer = false;
var factory = config.BuildSessionFactory();
interceptor.SessionFactory = factory;

We set up our stan­dard stuff — map­ping and con­nec­tion string. Then we need to tell NHiber­nate to use our cus­tom Prox­y­Fac­to­ry­Fac­tory. Then we build con­fig­u­ra­tion object and set our cus­tom inter­cep­tor to it. Hav­ing done that we can build ses­sion fac­tory and give the inter­cep­tor ref­er­ence to the ses­sion fac­tory. Cer­tainly not the smoothest ride but gets the job done. Oh — and as I men­tioned we dis­able reflec­tion opti­mizer so that we don't have to over­ride yet another class (two actually).

That is all it takes to be able to get rid of all the seem­ingly super­flu­ous con­struc­tors and have a much sim­pler model.

Well not quite — what about the activator

Right — the acti­va­tor. How do we make that hap­pen? Here's all the code in this class.

public class NHibernateActivator : INHibernateActivator
{
	public bool CanInstantiate(Type type)
	{
		return true;
	}

	public object Instantiate(Type type)
	{
		return FormatterServices.GetUninitializedObject(type);
	}
}

Remem­ber how I said that NHiber­nate can be viewed as fancy seri­al­izer? Here we make it obvi­ous by using System.Runtime.Serialization.FormatterServices class to give us an unini­tial­ized instance of given type. Unini­tial­ized means that all the fields will be null or 0 and no code will be ran. This how­ever is pre­cisely what we want for the rea­sons out­lined in pre­vi­ous post. We then throw the object to NHiber­nate machin­ery to per­form all the nec­es­sary ini­tial­iza­tion for us, so that when the object is returned from the ses­sion it is fully cre­ated and usable. We could also imple­ment a mech­a­nism sim­i­lar to one of the options that stan­dard .NET seri­al­iza­tion pro­vides to allow the object to ini­tial­ize its volatile state.

Final words

That is all it takes to make the model a bit more per­sis­tence igno­rant. Like I said this approach won't work always. It requires full trust envi­ron­ment and prob­a­bly if you have com­plex volatile state the solu­tion will be too sim­plis­tic. I would be inter­ested to hear what do you think about the approach in gen­eral. Can you spot any severe short­com­ings or flaws? Do you like it? Would you use it?

NHibernate and default constructors

One of the first things you learn about NHiber­nate is that in order for it to be able to con­struct your instances and take advan­tage of lazy load­ing every per­sis­tent class must have the default, para­me­ter­less con­struc­tor. This leads to hav­ing enti­ties look­ing like this (stan­dard blog with posts and com­ments example).

 public class Post { private readonly IList<comment> comments = new List<comment>();
    private Blog blog;

    [Obsolete("For NHibernate")]
    protected Post()
    {
       
    }

    public Post(string title, string body, Blog blog)
    {
        Blog = blog;
        Title = title;
        Body = body;
        Published = DateTimeOffset.Now;
    }

    public virtual int Id { get; private set; }
    public virtual DateTimeOffset Published { get; private set; }

    public virtual string Title { get; set; }
    public virtual string Body { get; set; }


    public virtual IEnumerable<comment> Comments
    {
        get { return comments; }
    }

    public virtual Blog Blog
    {
        get { return blog; }
        set
        {
            if (blog != null)
            {
                throw new InvalidOperationException("already set");
            }
            blog = value;
            if (blog != null)
            {
                blog.AddPost(this);
            }
        }
    }

    [EditorBrowsable(EditorBrowsableState.Never)]
    protected internal virtual void AddComment(Comment comment)
    {
        comments.Add(comment);
    }
}

Notice the first con­struc­tor. It doesn’t do any­thing. As the obso­lete mes­sage (which is out there to get com­pi­la­tion warn­ing in case some devel­oper acci­dently calls this con­struc­tor in their code) points out – this con­struc­tor is there only so that NHiber­nate can do its magic. Some peo­ple do put there ini­tial­iza­tion logic for col­lec­tions, (espe­cially when you use auto­matic prop­er­ties) but I use fields and ini­tial­ize them inline. In that case the con­struc­tor is pretty much use­less. I started think­ing why is it even there and that per­haps it doesn’t really belong to the class. But let’s start at the beginning.

What is a constructor

As basic as the ques­tion may seem, it is use­ful to remind our­selves why we need con­struc­tors at all. The best book about C# and .NET defines them as follows:

Con­struc­tors are spe­cial meth­ods that allow an instance of a type to be ini­tial­ized to a good state.

Notice two impor­tant things about this def­i­n­i­tion. First, it doesn’t say that con­struc­tor cre­ates the instance or that con­struc­tors are the only way to cre­ate the instance. Sec­ond, con­struc­tors ini­tial­ize newly cre­ated object to their ini­tial state so that any­thing that uses the object after­wards deals with fully con­structed, valid object.

Con­struc­tors and persistence

The above def­i­n­i­tion very well applies to the other con­struc­tor we have on the Post class. That con­struc­tor ini­tial­izes the Post to a valid state. In this case valid means the following.

  • Post is part of a blog – we can’t have a post that lives on its own. Our posts need to be part of a blog and we make this require­ment explicit by requir­ing a Blog instance to be pro­vided when con­struct­ing Post.
  • Post requires a title and a body and that’s why we also require those two prop­er­ties to be pro­vided when con­struct­ing a post.
  • Posts are usu­ally dis­played in a inverse chrono­log­i­cal order hence we set the Pub­lished timestamp.

We do none of the above in the other, “nhiber­nate” con­struc­tor. That means that accord­ing to the def­i­n­i­tion of a con­struc­tor it is not really doing what a con­struc­tor is sup­posed to be doing. It is never used to con­struct an object.

Hydra­tion

Let’s take a step back now. What NHiber­nate is doing with objects in nut­shell is seri­al­iza­tion. You cre­ate an object in your code and ini­tial­ize it using con­struc­tor, do some stuff with it and then you save the object away, so that it can be retrieved later, after your app has been closed, or per­haps on another server instance. You save away the state of the object so that the state rep­re­sen­ta­tion of the object can live longer than volatile, in-memory rep­re­sen­ta­tion of the object. If you fol­low this path of though the next obvi­ous con­clu­sion is that if you have a load-balanced sys­tem and two server instances work with Post#123 they both are deal­ing with the same object, even though they are two sep­a­rate machines.

The con­clu­sion of that is that when NHiber­nate is retriev­ing an object from the per­sis­tent store it is not con­struct­ing it. It is recre­at­ing an in-memory rep­re­sen­ta­tion of an object that had been cre­ated and per­sisted pre­vi­ously. Hence we are merely recre­at­ing object that already has a well known state and had been ini­tial­ized and just pro­vid­ing dif­fer­ent rep­re­sen­ta­tion for it. This process is called hydration.

Per­sis­tent and Volatile state

The full pic­ture is a bit more com­pli­cated than what I painted so far. The data­base and in-memory object are two rep­re­sen­ta­tion of the same entity but they don’t have to be fully one to one. Specif­i­cally it is pos­si­ble for the in-memory rep­re­sen­ta­tion to have state beyond the per­sis­tent state. In other words the in-memory object may have some prop­er­ties that are spe­cific to it, and not rel­e­vant to the in-database rep­re­sen­ta­tion. A con­ve­nient exam­ple that most peo­ple will be able to relate to would be a log­ger. Please don’t quote me as advo­cat­ing using log­ging in your enti­ties but log­ger is one of the things you may want to have on your in-memory object and use it while exe­cut­ing code in your appli­ca­tion but then let them go once you no longer need the object and not per­sist them. If we had one in the Post class the empty con­struc­tor would change to the following:

[Obsolete("For NHibernate")]
protected Post()
{
    logger = LoggerProvider.LoggerFor(typeof(Post));
}

If we don’t use con­struc­tor for recre­ation of the object, how can we get the log­ger in? How do we make NHiber­nate hold the con­truc­tor seman­tics and give us fully ini­tial­ized object? Remem­ber I said one way of look­ing at NHiber­nate from the object’s per­spec­tive is that’s just a fancy serializer/deserializer. Turns out seri­al­iza­tion mech­a­nism in .NET offers us four(that I know of, pos­si­bly more) ways of tack­ing this issue

  • you can use seri­al­iza­tion sur­ro­gate that knows how to recre­ate the full state of the object
  • you can use dese­ri­al­iza­tion call­back inter­face to be noti­fied when the object has been fully dese­ri­al­ized and then ini­tial­ize the volatile state.
  • you can use seri­al­iza­tion call­back attrib­utes to be noti­fied when var­i­ous steps in the serialization/deserialization process hap­pen and ini­tial­ize the volatile state.
  • you can use ISe­ri­al­iz­able inter­face and imple­ment seri­al­iza­tion con­struc­tor which is used to dese­ri­al­ize the object.

Notice that only one of those approaches uses spe­cial con­struc­tor. Since as we dis­cussed NHiber­nate doesn’t really need the default con­struc­tor (in the­ory that is), can we really get rid of it? Turns one we can (in most cases), and we’ll look at how to do it in the next post.

Testing with NHibernate and SQLite

warninglabel

There does not seem to be too much details on how to set up a test envi­ron­ment for NHiber­nate test­ing using SQLite. Ayende has a nice post on this, but he does not go into details of how, what and where, so I decided to fill in the blanks, and pro­vide an up to date sam­ple for NHiber­nate 2.1.

Let’s first gather all the things we need:

Now we need to add ref­er­ences to all these projects. Make sure you add cor­rect ref­er­ence to System.Data.SQLite (either x86 ver­sion from the main direc­tory, or x64 ver­sion from x64 folder if you’re run­ning on 64bits).

You also can’t add ref­er­ence to sqlite3.dll, because it’s an unman­aged dll. I sim­ply add it as ele­ment to solu­tion and set it to copy to out­put direc­tory. After all, your solu­tion should look roughly like this:

NHibernate_tests

I also have a base class for my tests that does all the setup for me. Here’s how it looks like:

[TestFixture]
public abstract class DbTestsBase<T>
{
    protected ISessionFactory factory;
    protected T sut;
 
    private string dbFile;
 
    public void Init(params Assembly[] assembliesWithMappings)
    {
        dbFile = GetDbFileName();
        EnsureDbFileNotExists();
 
        NHibernateProfiler.Initialize();
        var configuration = new Configuration()
            .AddProperties(new Dictionary<string, string>
                               {
                                   { Environment.ConnectionDriver, typeof( SQLite20Driver ).FullName },
                                   { Environment.Dialect, typeof( SQLiteDialect ).FullName },
                                   { Environment.ConnectionProvider, typeof( DriverConnectionProvider ).FullName },
                                   { Environment.ConnectionString, string.Format( "Data Source={0};Version=3;New=True;", dbFile) },
                                   { Environment.ProxyFactoryFactoryClass, typeof( ProxyFactoryFactory ).AssemblyQualifiedName },
                                   { Environment.Hbm2ddlAuto, "create" },
                                   { Environment.ShowSql, true.ToString() }
                               });
        foreach (var assembly in assembliesWithMappings)
        {
            configuration.AddAssembly(assembly);
        }
 
        new Remapper().Remap(configuration);
 
        factory = configuration.BuildSessionFactory();
    }
 
    [TearDown]
    public void TearDownTests()
    {
        factory.Dispose();
        EnsureDbFileNotExists();
        NHibernateProfiler.Stop();
    }
 
    private string GetDbFileName()
    {
        var path = Path.GetFullPath(Path.GetRandomFileName() + ".Test.db");
        if (!File.Exists(path))
        {
            return path;
        }
 
        // let's try again
        return GetDbFileName();
    }
 
    private void EnsureDbFileNotExists()
    {
        if (File.Exists(dbFile))
        {
            File.Delete(dbFile);
        }
    }
}

There are cou­ple inter­est­ing points in this code:

I expose the Ses­sion­Fac­tory, not Ses­sion. That’s because I use this class for test­ing repos­i­to­ries in state­ful appli­ca­tion, that man­age the ses­sion themselves.

I save the data­base to file, instead of keep­ing it in mem­ory like Ayende does. That’s con­nected to the pre­vi­ous fact. Appar­ently, in-memory data­base only lives as long as ses­sion that cre­ated it, which does not cut it for me.

I then use the class like this:

[TestFixture]
class Entity1Tests : DbTestsBase<Entity1>
{
    [SetUp]
    public void SetUp()
    {
        base.Init(typeof(Entity1).Assembly);
    }
 
    [Test]
    public void Member_should_action()
    {
        //some code
    }
}

Pretty sim­ple and so far, cov­ers my needs.

Tech­no­rati Tags: ,,

Storing long text and binary blobs with NHibernate

There comes a time when you have to store in the data­base not only pretty objects but also some not so pretty data. For exam­ple, let’s take the clas­si­cal entity – the invoice.

 

Let’s say your appli­ca­tion can receive invoice in three ways: by its own fron­tend, by email in rtf file, and by fax. In two later cases you may have a require­ment to store the rtf file and the scanned fax as a proof in the data­base. How to approach that?

Let’s start by sketch­ing our Invoice class:

public class Invoice
{
    public virtual Guid Id { get; protected set; }
    public virtual string InvoiceRtfString { get; set; }
    public virtual byte[] ScannedInvoiceJpg { get; set; }
    
    //a lot more stuff...
}

For the sake of exam­ple let’s say we want to keep the rtf file as text (well, that’s what it is under­neath), and we want to keep the scanned invoice as byte array.

Let’s cre­ate the sim­plest map­ping and see what NHiber­nate will pro­duce out of it.

<?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"/>
    <property name="ScannedInvoiceJpg"/>
  </class>
</hibernate-mapping>

If we now ask NHiber­nate to gen­er­ate the schema for us, that is what it will produce:

create table Invoice (
    Id UNIQUEIDENTIFIER not null,
   InvoiceRtfString NVARCHAR(255) null,
   ScannedInvoiceJpg VARBINARY(8000) null,
   primary key (Id)
)

As you can see, we get quite lit­tle space for our Rtf file – hardly any file will fit in 255 char­ac­ters, and cer­tainly not one cre­ated by Microsoft Word.

If you check NHiber­nate doc­u­men­ta­tion it sug­gests using String­Clob for this, so let’s do just that. It also sug­gests we used Bina­ry­Blob type for the scanned jpg so let us apply this change as well, and see how it affects the gen­er­ated schema.

If we update the 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"/>
    <property name="ScannedInvoiceJpg" type="BinaryBlob"/>
  </class>
</hibernate-mapping>

…and gen­er­ate schema…

create table Invoice (
    Id UNIQUEIDENTIFIER not null,
   InvoiceRtfString NVARCHAR(255) null,
   ScannedInvoiceJpg VARBINARY(8000) null,
   primary key (Id)
)

…it will sur­pris­ingly be exactly the same. I’m gen­uinely sur­prised. Is there any­thing else we can do?

Quick googling leads to this old post by Ayende, where he sug­gests the solu­tion: spec­i­fy­ing sql-type explic­itly as NTEXT for the string column.

How­ever, as Scott White noticed, NTEXT is dep­re­cated since SQL Server 2008, we should use nvarchar(max) instead. Since we also expect size of seri­al­ized jpg images to be higher than 8kb, we’ll use varbinary(max) instead here as well.

So our final map­ping looks like this:

<?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>

And NHiber­nate pro­duces the fol­low­ing DDL out of it:

create table Invoice (
    Id UNIQUEIDENTIFIER not null,
   RtfText nvarchar(MAX) null,
   JpgData varbinary(max) null,
   primary key (Id)
)

Which is exactly what we needed.

DNK Tags:

Two way one-to-many associations in NHibernate

As nice as the exam­ple from my pre­vi­ous post was (per­son hav­ing pets) it exhibits a prob­lem. The prob­lem is related to the fact that by their very nature asso­ci­a­tions in rela­tional data­bases are bidi­rec­tional, whereas in objects they are uni­di­rec­tional. Here we hit the myth­i­cal imped­ance mis­match.

Often how­ever we want to have a bidi­rec­tional asso­ci­a­tion in our object model. Per­son may have a set of pets, but then each pet has its owner. Then we have another prob­lem. What if we add a pet to person’s pet col­lec­tion, but for­get to set pet’s owner? We’ll get inconsistencies.

The best way to alle­vi­ate that (or the best way I found. Remem­ber that the big warn­ing sign from the pre­vi­ous post still holds true) is to decide on using one side of asso­ci­a­tion for manip­u­la­tion, and have it mod­ify the other.

public class Pet
{
    private Person _owner;
    public virtual Guid Id { get; protected set; }
    public virtual string Name { get; set; }
 
    public virtual Person Owner
    {
        get { return _owner; }
        set
        {
            if (Equals(_owner, value))
            {
                //there's no need to change anything
                return;
            }
            //sorry old owner, I'm no longer yours
            if (_owner != null)
            {
                _owner.Pets.Remove(this);
            }
            _owner = value;
            if (_owner != null)
            {
                //welcome to my new home
                _owner.Pets.Add(this);
            }
        }
    }
}

Here you see that when we set the Owner for a pet it takes care of remov­ing the pet from the old owner, and adding it to the new one.

Is it all we need? Well, not quite, we for­got about the mapping.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="ConsoleApplication1" assembly="ConsoleApplication1">
  <class name="Pet">
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <property name="Name"/>
    <many-to-one name="Owner" column="OwnerId" />
  </class>
</hibernate-mapping>

Notice one impor­tant thing. In our many-to-one we have set the value of col­umn attribute to be the same as the one-to-many end’s key col­umn attribute (see Per­son’ map­ping in the pre­vi­ous post or below). If we didn’t NHiber­nate would cre­ate two dif­fer­ent columns for that and I’m not sure how it would affect the behav­ior. Prob­a­bly it’s some­thing you’d want to avoid.

Are we done? Let’s see.

using(var session = factory.OpenSession())
using(var transaction = session.BeginTransaction())
{
    var krzysztof = new Person();
    new Pet {Name = "Rex", Owner = krzysztof};
    session.Save(krzysztof);
    transaction.Commit();
}

When we run that piece of code, with the map­ping we have, here’s what will happen.

nh_2_additional_update

NHiber­nate will issue two INSERTS and one UPDATE (this is exactly the same SQL as code from my pre­vi­ous post would yield. The dif­fer­ence is, we can get rid of the UPDATE now). NHiber­nate Pro­filer shows us an alert by the UPDATE say­ing that its super­flu­ous and if we used inverse=”true” it would go away. So let’s do just that.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="ConsoleApplication1" assembly="ConsoleApplication1">
  <class name="Person">
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <property name="HasPets" access="readonly"/>
    <set name="Pets" cascade="all" inverse="true" >
      <key column="OwnerId" />
      <one-to-many class="Pet" />
    </set>      
  </class>
</hibernate-mapping>

If we run the appli­ca­tion now, the addi­tional UPDATE will go away, as advertised.

nh_2_no_update

Ok, we can INSERT our asso­ci­a­tion into the DB, so let’s now SELECT it back.

using(var session = factory.OpenSession())
using(var transaction = session.BeginTransaction())
{
    var krzysztof1 = session.Get<Person>(id);
    foreach(var pet in krzysztof1.Pets)
        Debug.Assert(pet.Owner == krzysztof1);
 
    transaction.Commit();
}

Sur­pris­ingly, if we run this code we’ll get an exception:

NHibernate.LazyInitializationException was unhan­dled
  Message="illegal access to load­ing collection"

The prob­lem is that when cre­at­ing Pet instances NHiber­nate sets the Par­ent prop­erty. Our set­ter tries to add the pet to Person’s Pets col­lec­tion which is not ini­tial­ized, hence the exception.

So how do we fix it? Same as the last time. We want to bypass the set­ter and set the owner directly into the field. We don’t need our setter’s code any­way since at this point NHiber­nate takes care of main­tain­ing integrity of the association.

So we only need to add appro­pri­ate access attribute to our many-to-one map­ping and we’re all set.

<many-to-one name="Owner" column="OwnerId" access="nosetter.camelcase-underscore" />

Hope this was helpful.

Read only collections and properties with NHibernate

warningsign

I’ve been work­ing with NHiber­nate for the last cou­ple of days, and as I make my way though it, I find out about things, that were not so obvi­ous to me at first, so I decided to post them here, so that some­one else can ben­e­fit as well.

First thing you learn about NHiber­nate (well ok – first thing I learned about NHiber­nate, but most of you prob­a­bly as well) is that it requires you to mark your prop­er­ties vir­tual, have para­me­ter­less con­struc­tor, and pay spe­cial atten­tion to your GetH­ash­Code() and Equals() methods.

With all that in mind (and fol­low­ing many tuto­r­ial that are out there) you may start crunch­ing your entity classes to look like this:

public class Person
{
    public virtual Guid Id { get; set; }
    public virtual ISet<Pet> Pets{ get; set; }
    public virtual bool HasPets 
    { 
        get { return Pets.Count > 0; } 
        set { /*do nothing*/}
    }
}

with map­ping like this:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="ConsoleApplication1" assembly="ConsoleApplication1">
  <class name="Person">
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <property name="HasPets"/>
    <set name="Pets" cascade="all" >
      <key column="OwnerId" />
      <one-to-many class="Pet" />
    </set>      
  </class>
</hibernate-mapping>

This gets the job done, but it’s far from being per­sis­tence igno­rant. You usu­ally don’t want to expose a set­ter for your col­lec­tions, so that they can be swapped. Also the set acces­sor on HasPets prop­erty is noth­ing short of an ugly hack. Although we have no explicit sign of NHiber­nate in the code, it is any­thing but per­sis­tence ignorant.

You can how­ever make it so.

public class Person
{
    private readonly ISet<Pet> _pets = new HashedSet<Pet>();
 
    public virtual Guid Id { get; protected set; }
 
    public virtual ISet<Pet> Pets { get { return _pets; } }
 
    public virtual bool HasPets
    {
        get { return Pets.Count > 0; }
    }
}

Now it looks like a “nor­mal” class. Will it work with NHiber­nate now though? – Absolutely*. The trick is to use map­ping files appropriately.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="ConsoleApplication1" assembly="ConsoleApplication1">
  <class name="Person">
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <property name="HasPets" access="readonly"/>
    <set name="Pets" cascade="all" access="nosetter.camelcase-underscore" >
      <key column="OwnerId" />
      <one-to-many class="Pet" />
    </set>      
  </class>
</hibernate-mapping>

 

What’s changed? I added the access attrib­utes to the mappings.

For HasPets I set it to read­only. That way NHiber­nate will read the prop­erty and use its value when doing INSERTs and UPDATEs, but will not include it in SELECTs.

For Pets one-to-many map­ping I used value that tells NHiber­nate to use the get­ter to read the value of the prop­erty, and to write to the field directly, and that field name is _pets (by con­ven­tion). There are quite a few more options, and you can use them to do some pretty pow­er­ful things, like enforc­ing con­sis­tency in two-way *-to-many mappings.

 

* the access=”readonly” is new to NHiber­nate v2.1

DNK Tags: