NHibernate Forge
The official new home for the NHibernate for .NET community

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 abr 08 2009, 04:07 a.m. by Ayende
Filed under:

Comments

Stefan Steinegger wrote re: NHibernate Mapping - <property/>
on 04-08-2009 6:32

Thanks a lot Ayende! I'm looking forward to your next mapping blog :-)

YJingLee wrote re: NHibernate Mapping - <property/>
on 04-08-2009 9:36

Thanks you post

Cristiano wrote re: NHibernate Mapping - <property/>
on 04-09-2009 4:31

There is some difference about performance if the optional parameters are specified or not? For example is it better specified every time the type, column, insert, update..., also are like the default? Until now I explicit everything because if the default change between two version my mapping continue to work, but only for this.

Dario Quintana wrote re: NHibernate Mapping - <property/>
on 04-09-2009 9:58

@Cristiano it's the same... also using defaults your eyes hurts less :-)

Srinivas_NHibernate_Rookie wrote re: NHibernate Mapping - <property/>
on 05-18-2009 6:18

Hi Guys , If attribute "Formula" returns more than one Row how best we can handle this in Mappings?

Can we use an Array type so that i can hold multiple rows to the mapped field ?

Ayende wrote re: NHibernate Mapping - <property/>
on 05-18-2009 6:30

You will get an error, there is no way SQL can return several rows inside a column

Srinivas_NHibernate_Rookie wrote re: NHibernate Mapping - <property/>
on 05-18-2009 9:53

@Ayende

Thanks for the Reply Ayende

In my application i am using a property as shown below:

<property name="x" access="field" formula="(select T.Col1 from Table_1 T where T.col2>0 )" type="Decimal"/>

My formula="(select T.Col1 from Table_1 T where T.col2>0 )"  would result in more than one row (i mean multiple values)

In this scenario how could i use the  property ?

Do i need to change the type to Array

if so could you pls let guide me .

Ayende wrote re: NHibernate Mapping - <property/>
on 05-18-2009 10:01

It is not possible.

Try to execute this SQL, and you'll get an error at the database level.

Srinivas_NHibernate_Rookie wrote re: NHibernate Mapping - <property/>
on 05-18-2009 11:06

@Ayende  

Yeah exactly i am getting Error

So ,We cannot use a Formula in NHibernate if SQL  yields more than one row or value

If i am not  right in interpreting this please correct me

Ayende wrote re: NHibernate Mapping - <property/>
on 05-18-2009 11:28

The problem is not with NH

The problem is that what you are trying to do isn't valid SQL in the relational model.

Srinivas_NHibernate_Rookie wrote re: NHibernate Mapping - <property/>
on 05-19-2009 1:03

@Ayende  

Thanks

Srinivas_NHibernate_Rookie wrote re: NHibernate Mapping - <property/>
on 05-26-2009 7:13

@Ayende  

I dont know will it make sense to me posting this question here

i have a scenario like this

<bag name="Collection1" cascade="all" inverse ="true">

<key column="Col_ID"/>

<one-to-many class="Collection1MappingClass" not-found="ignore"/>

</bag>

if i want only the collection of one particular column in "Collection1" table do i need to use <element> tag instead of <one -to many> or can i use both inside the bag.

bunceg wrote re: NHibernate Mapping - <property/>
on 05-27-2009 9:25

Jumping on Ayende's blog but I think this sort of query should be raised in the general help forum that you can find under "Groups". it's probably better than adding a growing list of "how do I do this" questions to the blog post.

Srinivas_NHibernate_Rookie wrote re: NHibernate Mapping - <property/>
on 07-23-2009 11:01

Hi Ayende and bunceg

i have an issue with <property> mappings

i am facing some precision problems with Oracle Number datatype and NHibernate Double datatype (prperty type is Double for the Oracle Column)

When i retrive the Oracle Number through NHibernate the value is appended by some more precision values .

Why is this happening in NHibernate is there any issue with the DataTypes i used?

Ayende wrote re: NHibernate Mapping - <property/>
on 07-23-2009 11:34

Srinivas,

You need to specify precision in the property tag.

Please ask the question in nh users, for more details.

Srinivas_NHibernate_Rookie wrote re: NHibernate Mapping - <property/>
on 07-23-2009 12:58

Thanks Ayende for the quick reply

Powered by Community Server (Commercial Edition), by Telligent Systems