Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,128 | Comments: 45,549

filter by tags archive

NHibernate Mapping - <many-to-one/>

time to read 5 min | 940 words

Next up for inspection is the <many-to-one/> element. This element is defined as:

        name="PropertyName"                                (1)
        column="column_name"                               (2)
        class="ClassName"                                  (3)
        cascade="all|none|save-update|delete"              (4)
        fetch="join|select"                                (5)
        update="true|false"                                (6)
        insert="true|false"                                (7)
        property-ref="PropertyNameFromAssociatedClass"     (8)
        access="field|property|nosetter|ClassName"         (9)
        unique="true|false"                                (10)
        optimistic-lock="true|false"                       (11)
        not-found="ignore|exception"                       (12)

Much of the attributes on this element are identical to the ones that I outlined in the post about <property/>. 1, 2, 3, 6, 7, 9 and 11 are identical, and I am not going to cover them.

4) cascade is interesting, it controls one of the more interesting NHibernate features, persistence by reachability.I outlined all the possible options in 2006, so I wouldn’t repeat them again.

5) fetch is really interesting. Let us take a look at an entity definition, and explore how modifying it can alter NHibernate’s behavior.

<class name="Post"
	<id name="Id">
		<generator class="identity"/>
	<property name="Title" />
	<many-to-one name="Blog" column="BlogId"/>

And we have the following code to exercise NHibernate:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
	var post = session.Get<Post>(1);

This would result in the following SQL.


But interesting things happen when we start playing with the fetch attribute. Note that by default the fetch attribute is defaulting to “select”, so setting it to that value is merely making things explicit, but setting it to fetch=”join”, like this:

<many-to-one name="Blog" 

Would result in the following SQL:


We eagerly load the Blog association, in this case.

8) property-ref is a legacy feature, it is meant to allow you to create many-to-one associations when the association is not done on the primary key of the association. In general, I would strongly suggest avoiding it.

9) unique is relevant only if you use NHibernate to specify your schema. This would generate a unique constraint when we generate the DDL.

12) not-found is another legacy feature, it controls how NHibernate behaves when it finds an invalid foreign key. That is, a value that points to an entity that doesn’t exist. By default, this would trigger an error, as this generally indicate a problem with the database, but with legacy database, you can tell it to set the property value to null instead.



I've found a few problems when using property-ref and natural keys so I would heartily recommend adding a column for a surrogate key when using nhibernate. It all works pretty well with surrogate keys.


Sucks that I've had to use both property-ref and not-found ... stupid legacy dbs!

Miki Watts

About not-found, is there a way to specify a different default value in case the foreign key is not found ? I've got a legacy database that has missing values, and doesn't allow nulls either.


Thanks for your series so far, it's good to see this.


Ayende, I have a question:

Let's say I have a 'Employee' - it has a many to one mapping to a Company

The Company in turn has a many to one to let's say a 'address'

Basically, if I set all these many -to-one's to 'fetch=join'

Will it propagate down when I get an employee ?

Meaning, when I ask for an employee it will join to company and company join to address in one call ?


Ayende Rahien


For that, you would need a custom IUserType to manage that.


Ayende - I posted this to nhusers about using "fetch='join'" vs FetchMode.Eager


Basically, setting fetch='join' has the desired effect, but setting FetchMode.Eager in my criteria doesn't have the same effect and I would expect that it does. I must be doing something slightly wrong.

Thanks - Luke

Ayende Rahien

That is because there is a difference between Eager and Join.

You should use Join or Select vs. Eager or Lazy


Ayende, thanks for your response. The FetchMode enum defines "Eager" and "Join" to be equivalent. Using "FetchMode.Join" still does not use a join in the output SQL.

namespace NHibernate


public enum FetchMode


    // Summary:

    //     Default to the setting configured in the mapping file.




    // Summary:

    //     Fetch eagerly, using a separate select. Equivalent to fetch="select" (and

    //     outer-join="false")



    // Summary:

    //     Fetch using an outer join. Equivalent to fetch="join" (and outer-join="true")





Anthony Dewhirst

Hi Ayende,

I am finding an issue with the fetch mode set to Join. I have two child collections in my parent class and fetch set to join on both my child classes in the mapping. If I create 2 children and save the mapping, when I reload, I have 4 in each collection. I understand that you will get 4 rows from the join, but I would have thought that NHiberante would have worked out the duplicate identities.

Parent Mapping: (The Children 1 and 2 just contains an Id)






The parent class:

using System.Collections.Generic;

namespace Domain


public class Parent : AbstractDomainObject


    #region Core Properties

    public virtual IList

<child1 Children1 { get; set; }

    public virtual IList

<child2 Children2 { get; set; }


    #region Constructors

    public Parent()


        Children1 = new List


        Children2 = new List






the program:

    static void Main(string[] args)


        Configuration cfg = new Configuration();


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

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

        ISessionFactory sessionFactory = cfg.BuildSessionFactory();

        using (var session = sessionFactory.OpenSession())

        using (var tx = session.BeginTransaction())


            var parent = new Parent();

            parent.Children1.Add(new Child1());

            parent.Children1.Add(new Child1());

            parent.Children2.Add(new Child2());

            parent.Children2.Add(new Child2());




        using (var session = sessionFactory.OpenSession())

        using (var tx = session.BeginTransaction())


            var parents = session.CreateCriteria(typeof (Parent)).List


            Console.WriteLine("There are {0} children1", parents[0].Children1.Count);

            Console.WriteLine("There are {0} children2", parents[0].Children2.Count);




I get that there are 4 children in each collection.

Am I using the wrong collection type or is this a known feature/bug in nhibernate?

Anthony Dewhirst

This time with the mapping....I hope

<id name="Id">

  <generator class="native"/>


<bag name="Children1" cascade="all-delete-orphan" lazy="false" generic="true" fetch="join">

  <key column="ParentId"></key>

  <one-to-many class="Child1" />


<bag name="Children2" cascade="all-delete-orphan" lazy="false" generic="true" fetch="join">

  <key column="ParentId"></key>

  <one-to-many class="Child2" />


Ayende Rahien


Please post this again in the mailing list, I'll look at it there.

Ayende Rahien


That is the expected behavior in this scenario if you are not using a set.

That is because NHibernate will use values from the database, and it has no way of knowing what you are actually intending to do with them.

Daniel Fernandes


Are there performance issues in having to use @property-ref for those kind of mappings ?

I'm dealing on a daily basis with a (horrible) legacy database and today I had this kind of association:

CATEGORYA one-to-many CATEGORYB and then


CATEGORY_A and B are using single table inheritance using a formula based discriminator.

The association between CATEGORYB and CATEGORYB_DATA is via @property-ref and it's set to use JOIN FETCHING.

If I load up a CATEGORYB object, NHibernate will correctly issue a LEFT OUTER JOIN and will retrieve all the necessary attributes to rehydrate CATEGORYB_DATA objects but then somehow I see further SELECT statements issued for each one of the CATEGORYBDATA that should have already been loaded using the JOIN FETCHING, those SELECT statements are constrained on the value of the @property-ref set on the many to one association.

Would using the @property-ref mess something in the identity map making NHibernate to reload again those same objects ?

I sometimes wonder if NHibernate is the best tool for totally screwed legacy databases....


Ayende Rahien


Those type of questions are best served in the NH Users mailing list



with fetch="select" option, it issues seperate select command for each of the many-to-one association if it exists even though i am not using the many-to-one part. is that the intended behaviour?

i thought with fetch="select" option, separate select command would be issued only when many-to-one property is selected.

i am using nhiberntate 2.1.


Ayende Rahien


fetch and lazy are two separate aspects


does that mean lazy-loading is not available for many-to-one?

thanks ayende

Ayende Rahien

many-to-one support lazy loading


my apologies ayende,

lazy="false" in my many-to-one class. no wonder i wasn't gettting expected results.


Comment preview

Comments have been closed on this topic.


  1. The worker pattern - 3 days from now

There are posts all the way to May 30, 2016


  1. The design of RavenDB 4.0 (14):
    26 May 2016 - The client side
  2. RavenDB 3.5 whirl wind tour (14):
    25 May 2016 - Got anything to declare, ya smuggler?
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats