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

fluent-nhibernatenhibernateone-to-many

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.

Best Answer

NH3 and above allow to correct save entities in case of uni-directional one-to-many mapping without annoying save null-save-update cycle, if you set both not-null="true" on <key> and inverse="false" on <one-to-many>

FluentNHibernate code snippet for that:

public class MasterMap : ClassMap<Master> 
{
    public MasterMap() 
    {
        Id(x => x.MasterId);
        Map(x => x.Name);
        HasMany(x => x.Details)
            .Not.Inverse()     //these options are very
            .Not.KeyNullable() //important and work only if set together 
            .Not.KeyUpdate()   //to prevent double update
            .Cascade.All();
    }
}
Related Topic