简体   繁体   中英

(Fluent) NHibernate: HasMany/References (bidirectional) + Cascade Save

How do I configure mappings for bidirectional mapping in the scenario of X references Y, Y has many Xs , so that when I add many Xs to the Y instance and save Y instance, it'll work properly?

to make the problem clear, here's the code:

ClientCompany model has HasMany ContactPerson related models:

public class ClientCompany
{
    // .... 
    public virtual ISet<ContactPerson> ContactPeople { get; set; }
}

// mapping:
HasMany(x => x.ContactPeople)
            .AsSet()
            .Inverse()
            .Cascade.All();

the ContactPerson has not-nullable "ClientCompany" field referencing the parent company:

public class ContactPerson
{
    // ....
    public virtual ClientCompany ClientCompany { get; set; }
}

References(x => x.ClientCompany).Not.Nullable();

calling this code:

sess.Save(new ClientCompany()
            {                    
                ContactPeople = new HashSet<ContactPerson>()
                {
                    new ContactPerson()
                }
            });

causes this exception:

not-null property references a null or transient value xxxx.ContactPerson.ClientCompany

this is just simplified case, I'm using AutoMapper in my real-world project so setting the reference manually is not the solution

The most important thinkg in ORM world, namely when using NHibernate, is:

ALWAYS set both sides of relation.

This is valid way, how to set both sides:

var person = new ContactPerson();
var company = new ClientCompany
{                    
    ContactPeople = new HashSet<ContactPerson>()
    {
        person,
    },
};
person.ClientCompany = company

sess.Save(company);

By mapping is the Person declared as responsible for its relation (the inverse mapping .Inverse() ).

And that means, that it must have set the relation to its parent. This relation is used later for INSERT statement... and it cannot be null.

There is no need to save company and person separatelly. The only essential and absolutely important thing is to set both reference sides. That is a MUST.

Not sure what you can do with auto mapper... but some kind of wrapping/shielding of the bi-directional setting could be some special method on the POCO object:

public class ClientCompany
{
    // .... 
    public virtual ISet<ContactPerson> ContactPeople { get; set; }
    public virtual AddPerson(ContactPerson person)
    {
        ContactPeople = ContactPeople ?? new HashSet<ContactPerson>();
        ContactPeople.Add(person);
        person.ClientCompany = this;
    }
}

Now we just have to call AddPerson() at the right time...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM