Logo

NHibernate

The object-relational mapper for .NET

NHibernate Mapping - <property/>

I am going to post a few things about NHibernate, going in depth into seemingly understood mapping. We will start with the most basic of them all: <property/>

<property
        name="propertyName"                 (1)
        column="column_name"                (2)
        type="typename"                     (3)
        update="true|false"                 (4)
        insert="true|false"                 (4)
        formula="arbitrary SQL expression"  (5)
        access="field|property|ClassName"   (6)
        optimistic-lock="true|false"        (7)
        generated="never|insert|always"     (8)
/>

1) is pretty obvious, it is the name of the property on the persistent class.

2) should be obvious as well, this is the column name in the database, which by default is the name of the property. This allows us to map a property to a column, and adds a small optimization if you have one to one mapping.

3) type is interesting. This is the CLR type of the property that we map, but it can also be used to customize the way that NHibernate works with our data types by specifying a custom IUserType.

4) should NHibernate update this property in the database when updating the object? Let us look at an example:

<property name="Title" update="false"/>

Given this mapping, and the following code:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
	var blog = session.Get<Blog>(6);
	blog.Title = "changed";

	tx.Commit();
}

NHibernate will not try to update the row:

image

Note that we have no update here, even though we updated the actual property value, and usually NHibernate will save that value.

5) insert behaves in much the same way, disabling inserts for a property. For example:

<property name="AllowsComments" insert="false"/>

And this code:

object id;
using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
	id = session.Save(new Blog
	{
		AllowsComments = true,
		CreatedAt = DateTime.Now,
		Subtitle = "test",
		Title = "test"
	});

	tx.Commit();
}

Produces:

image

Note that we don't insert the AllowComments column. And if we try to update this entity:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
	var blog = session.Get<Blog>(id);
	blog.AllowsComments = false;
	blog.Title = "blah";

	tx.Commit();
}

We would get...

image

An update of AllowComments, but not of Title.

5) formula is a way to specify any arbitrary SQL that we want to associate with a property. Obviously, this is a read only value, and it is something that we would use on fairly rare occasions. Nevertheless, it can be pretty useful at times. Let us take a look at the mapping:

<property name="CountOfPosts"
	formula="(select count(*) from Posts where Posts.Id = Id)"/>

And selecting an entity will now result in:

image

Note that the formula was slightly preprocessed in order to make it work as a subquery.

6) access determines how we are going to actually set and get the actual value with NHibernate. We aren't limited to a simple public property, in fact, we can use: private variables, private auto property variable, custom implementation, field, and many more. This isn't actually very interesting at the moment to me, so I am just going to mention it and move on.

7) optimistic-lock is pretty complex, I am afraid. Mostly because it is a way to interact with the <version/> option of NHibernate. NHibernate has intrinsic support for optimistic concurrency, but sometimes there are reasons that you don't want to change the value of the version of the entity if a particular value changed. This is the role that optimistic-lock plays.

It will probably be better when we see the code. Let us take the following entity definition:

<class name="Blog"
	   table="Blogs">
  
	<id name="Id">
		<generator class="identity"/>
	</id>
	<version name="Version"/>
	<property name="Title" update="false"/>
	<property name="Subtitle"/>
	<property name="AllowsComments" insert="false"/>
	<property name="CreatedAt" />
	<property name="CountOfPosts"
		formula="(select count(*) from Posts where Posts.Id = Id)"/>
</class>

And now execute the following code:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
	var blog = session.Get<Blog>(1);
	blog.Subtitle = "new value 6";
	tx.Commit();
}

The SQL that is going to be executed is:

image

Note that we increment the value of the version column. But, if we specify optimistic-lock="false"...

<property name="Subtitle"
	optimistic-lock="false"/>

We will get:

image

Note that in this case, we do not increase the value of the version column.

8) generated is an instruction to NHibernate that the value of this property is set by the database, usually using a default value (in which case you'll use "insert") or a trigger (in which case you'll use "always").

When we use it like this:

<property name="AllowsComments" generated="insert"/>

And execute the following code:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
	session.Save(new Blog
	{
		CreatedAt = DateTime.Now,
		Title = "hello",
		Subtitle = "world",
	});
	tx.Commit();
}

We will get an insert followed immediately by a select:

image \

And the select is:

image

So we have to get it back from the database before we can actually make any sort of use of it.

And that was my in depth tour into <property/>, more will probably follow...


Posted Tue, 07 April 2009 05:07:13 PM by Ayende
Filed under: mapping

comments powered by Disqus
© NHibernate Community 2024