简体   繁体   English

(流畅)NHibernate:HasMany /参考(双向)+级联保存

[英](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? X引用Y的情况下,如何为双向映射配置映射,Y具有多个X ,以便在向Y实例添加多个X并保存Y实例时,它可以正常工作?

to make the problem clear, here's the code: 为了使问题更清楚,下面是代码:

ClientCompany model has HasMany ContactPerson related models: ClientCompany模型具有HasMany ContactPerson相关模型:

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: ContactPerson具有引用父公司的不可为空的“ ClientCompany”字段:

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 not-null属性引用的是null或瞬态值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 这只是简化的情况,我在现实世界的项目中使用了AutoMapper,因此手动设置引用 不是解决方案

The most important thinkg in ORM world, namely when using NHibernate, is: 在ORM世界中,最重要的想法是使用NHibernate时:

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() ). 通过映射被声明为负责其关系的Person (逆映射.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. 以后将这个关系用于INSERT语句...,并且不能为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: 不确定如何使用自动映射器...但是双向包装的某种包装/屏蔽可能是POCO对象上的一些特殊方法:

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... 现在我们只需要在正确的时间调用AddPerson()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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