Search code examples
nhibernatefluent-nhibernateone-to-many

NHibernate configuration for uni-directional one-to-many relation


I'm trying to set up a relationship as follows. Each Master item has one or more Detail items:

public class Detail {
    public virtual Guid DetailId { get; set; }
    public virtual string Name { get; set; }
}
public class Master {
    public virtual Guid MasterId { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<Detail> Details { get; set; }
}

And Mappings:

public class MasterMap : ClassMap<Master> 
{
    public MasterMap() 
    {
        Id(x => x.MasterId);
        Map(x => x.Name);
        HasMany(x => x.Details).Not.KeyNullable.Cascade.All();
    }
}
public class DetailMap : ClassMap<Detail> 
{
    public DetailMap() 
    {
        Id(x => x.Id);
        Map(x => x.Name);
    }
}

The Master database table is:

masterId   uniqueidentifier NOT NULL
name       nvarchar(max) NULL

and Detail is:

DetailId   uniqueidentifier NOT NULL
name       nvarchar(max) NULL
MasterId   uniqueidentifier NULL
foreign key (masterId) references [Master]

I don't really care to have a link from Detail back to Master -- in otherwords, Detail objects on their own are just not interesting to my domain layer. They will always be accessed via their Master object.

Using code like this:

Master mast = new Master 
{
    MasterId = new Guid(),
    Name = "test",
    Details = new List<Detail> 
    {
        new Detail { .DetailId = new Guid(), .Name = "Test1" },
        new Detail { .DetailId = new Guid(), .Name = "Test1" }
    }
};

using (transaction == Session.BeginTransaction) 
{
    Session.Save(mast);
    transaction.Commit();
}

This works great, except for a crazy limitation outlined in this post: NHibernate does an INSERT and puts Detail.MasterId as NULL first, then does an UPDATE to set it to the real MasterId.

Really, I don't want Detail entries with NULL MasterIds, so if I set the MasterId field to NOT NULL, the INSERT to Detail will fail, because as I said NHibernate is trying to put in MasterId = NULL.

I guess my question boils down to this:

How can I get the above code sample to work with my existing domain model (eg, without adding a Detail.Master property), and the Detail.MasterId field in the database set to NOT NULL?

Is there a way to get Nhibernate to just put the correct MasterId in the initial INSERT, rather than running an UPDATE afterwards? Is there rationale somewhere for this design decision? -- I'm struggling to see why it would be done this way.


Solution

  • You can't. To quote the link from my answer on the other question you linked to:

    Very Important Note: If the <key> column of a <one-to-many> association is declared NOT NULL, NHibernate may cause constraint violations when it creates or updates the association. To prevent this problem, you must use a bidirectional association with the many valued end (the set or bag) marked as inverse="true". See the discussion of bidirectional associations later in this chapter.

    Edit: as Hazzik has rightly pointed out, this has changed in NHibernate 3 and above. The docs sadly haven't been updated, so here's Hazzik:

    [If you] set inverse="false" and not-null on <key>, NH3 and above will perform only two inserts insead of insert-insert-update.