NHibernate一对一映射 - 不保存完整对象图

时间:2014-11-10 17:37:03

标签: nhibernate nhibernate-mapping

我试图让NHibernate在一对一的映射方案中保存完整的对象图。我有以下课程

public class Employee : EntityBase
{
    public virtual string EmployeeNumber { get; set; }
    public virtual Address ResidentialAddress {get; set; }
}

public class Address : EntityBase
{
    public virtual string AddressLine1 { get; set; }
    public virtual string AddressLine2 { get; set; }
    public virtual string Postcode { get; set; }
    public virtual string City { get; set; }
    public virtual string Country { get; set; }
    public virtual Employee Employee { get; set; }
}

我试图在这里使用一对一的映射,这样一个员工只有一个住址。我的映射在

之下
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Domain" namespace="Domain">
  <class name="Employee">
    <id name="Id" generator="hilo" />
    <property name="EmployeeNumber" length="10" />
    <one-to-one name="ResidentialAddress" class="Address" property-ref="Employee" cascade="all" />    
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Domain" namespace="Domain">
  <class name="Address">
    <id name="Id" generator="hilo" />
    <property name="AddressLine1"/>
    <property name="AddressLine2" />
    <property name="Postcode" />
    <property name="City" />
    <property name="Country" />

    <many-to-one name="Employee" class="Employee" unique="true" />

  </class>
</hibernate-mapping>

我使用以下代码来保存员工对象的实例

using (var transaction = Session.BeginTransaction())
        {
            id = Session.Save(new Employee
            {
                EmployeeNumber = "123456789",
                ResidentialAddress = new Address
                {
                    AddressLine1 = "Address line 1",
                    AddressLine2 = "Address line 2",
                    Postcode = "postcode",
                    City = "city",
                    Country = "country"
                }
            });
            transaction.Commit();
        }

在上述情况下,返回Employee的地址上的外键始终为null。但是,如果我在ResidentialAddress类上更改R Employee属性,以便Employee属性始终正确填充,如下所示

private Address address;
    public virtual Address ResidentialAddress
    {
        get { return address; }
        set
        {
            address = value;

            if (value != null) value.Employee = this;
        }
    }

这使它完美地运作。为什么我必须设置ResidentialAddress.Employee?我错过了映射中的内容吗? NHibernate是否应该自动保存完整的对象图(因此确定正确的外键值)。

以上工作代码与我有关,因为在从数据库加载实体期间从NHiberante调用时可能会产生问题。

1 个答案:

答案 0 :(得分:1)

你没有遗漏任何东西。

  

我们(开发人员)应始终关注设置任何双向关系的两端。

当我们使用one-to-many (没有反向=&#34; true&#34;)而没有设置many-to-one时,我们总是会遇到冗余且无效的序列SQL语句:

  • INSERT子记录,将NULL放入Parent_ID
  • 更新子记录,使用Parent.ID
  • 设置Parent_ID

不建议这样做:6.8. Bidirectional Associations

  

...非反面用于将内存中表示保存到数据库。如果两者都触发更改,我们将获得一个不必要的INSERT / UPDATE,甚至可能是外键冲突!对于双向一对多关联,当然也是如此......

所以,这是一对多,多对一。


如果是一对一

如上所述,没有集合持久存在。没有人在中间,会照顾另一端,并且发出“无效的”#34; INSERT和稍后更新。 NHibernate将使用EmployeeAddress的标准实体持久性。

关系(员工地址)的每个关联结束都有自己的持久性。这些可以在级联中触发(通常好的想法是<one-to-one ... cascade="all" />

但是每个持久化程序都需要足够的信息来创建正确的INSERT或UPDATE语句。即甚至C#地址必须知道其员工。 Address persister,将单独处理INSERT / UPDATE,只能访问Address实例。

总结:我们必须在代码中设置两端....即使我们没有强制(具有可空父列的非逆子映射),这也是很好的做法。
  BTW:一旦从数据库加载,我们希望 NHibernate 将设置两者结束...为什么我们不应该这样做?