【问题标题】:NHibernate one-to-one mapping - full object graph is not savedNHibernate 一对一映射 - 不保存完整对象图
【发布时间】:2014-11-10 17:37:03
【问题描述】:

我试图让 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();
        }

在上述情况下,Address back to Employee 上的外键始终为空。但是,如果我更改 Employee 类上的 RResidentialAddress 属性,以便始终正确填充 Employee 属性,如下所示

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

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

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

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

【问题讨论】:

  • 在地址映射上尝试

标签: nhibernate nhibernate-mapping


【解决方案1】:

您没有遗漏任何东西。

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

当我们使用one-to-many (without inverse="true") 并且没有设置many-to-one 时,我们总是会得到冗余且低效的SQL 语句序列:

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

不建议这样做:6.8. Bidirectional Associations:

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

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


一对一的情况

如上所述,没有收集持久化器。中间没有人,它会关心另一端,并发出“低效”的 INSERT 和后来的 UPDATE。 NHibernate 将为EmployeeAddress 使用标准实体持久化器。

关系(Employee-Address) 的每个关联端都有自己的持久化器。这些可以在级联中触发(通常最好有&lt;one-to-one ... cascade="all" /&gt;

但是每个持久化器都需要足够的信息来创建正确的 INSERT 或 UPDATE 语句。 IE。甚至 C# Address 也必须知道它的 Employee。 Address 持久化器将单独处理 INSERT/UPDATE,仅访问 Address 实例。

总结:我们必须在代码中设置两端......即使我们没有被强制(具有可为空的父列的非反向子映射),这也是一种好习惯
顺便说一句:一旦从 DB 加载,我们希望 NHibernate 将设置两个 端...为什么我们不应该这样做呢?

【讨论】:

  • 我明白你在 SQL 语句序列效率低下的观点。我想知道的最重要的事情是 NHibernate 是否能够为我进行双向图形保存,而无需我在代码中设置两端。在one-to-one 的情况下似乎不是。回复:一旦从数据库加载,我们期望 NHibernate 将设置两端......为什么我们不应该这样做呢? - 我不确定我上面的代码是否会在 NH 从数据库加载实体时产生问题。
  • 我只是想鼓励你(尽可能地)分配双方。再多几行......并设置两端。您甚至可以扩展 Employee 的属性设置器 ResidentialAddress 和内部设置 value.Employee = this; ...因此您的代码将保持不变,但将设置关系...希望这会有所帮助;)而且,您的代码不会创建NHibernate 在加载过程中的问题。真正的问题是插入。两端都必须设置..是唯一正确的答案。
猜你喜欢
  • 1970-01-01
  • 2011-06-14
  • 1970-01-01
  • 2013-09-23
  • 1970-01-01
  • 2010-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多