小编典典

使用NHibernate进行一对多映射的最小和正确方法

c#

我是NHibernate和C#的新手,所以请保持柔和!

我有以下两个NHibernate实体:

Employee
{
    private long _id;
    private String _name;
    private String _empNumber;
    private IList<Address> _addresses;

    //Properties...
}

Address
{
    private long _id;
    private String _addrLine1;
    private String _addrLine2;
    private String _city;
    private String _country;
    private String _postalCode;

    //Properties
}

并且他们之间有一个one-to-manyEmployee到的关系Address (每个员工的记录中可以有多个地址)
。方便地忽略了一个事实,即一个以上的员工可能居住在同一地址。

我从内存中的对象(NHibernate实体)的角度理解了这一点。我正在努力的是映射文件(这里我举一个简单的例子)。到目前为止,这是我想出的:

// Intentionally left out XML and <hibernate-mapping> 
// Mappings for class 'Employee'. -->
<class name="Employee" table="Employees">
    <id name="ID">
        <generator class="native">
    </id>

    <property name="Name" />
    <property name="EmpNumber" />

    <bag name="Addresses">
        <key column="AddressId" />
        <one-to-many class="Address" />
    </bag>
</class>

// Intentionally left out XML and <hibernate-mapping> .
// Mappings for class 'Address'
<class name="Address" table="Addresses">
    <id name="ID">
        <generator class="native">
    </id>

    // Intentionally left out name="Employee" 
    // as I don't have corresponding field in Address entity.
    <many-to-one class="Employee" column="EmployeeID" cascade="all" />

    <property name="AddrLine1" />
    <property name="AddrLine2" />
    <property name="City" />
    <property name="Country" />
    <property name="PostalCode" />
</class>
  1. 它是否正确?
  2. 如果没有,似乎我在这里缺少的是Address 实体中的字段,该字段是对相应Employee实体的引用。但是,如果是这样,那么我就不明白为什么要这样做:我不需要Address从那里获取 Employee,而只需从相反的方向获取…

阅读 326

收藏
2020-05-19

共1个答案

小编典典

仅提供一些提示,总结了我在使用NHibernate时发现的最合适的标准。

1)如果在持久性 (DB列)中 存在 双向* 引用,则也以 双向 代码表示。 __C# *

换句话说,如果 孩子 引用了 parent ,那么 父母 应该引用 child

public class Employee
{
    ...
    public virtual IList<Address> { get; set; }
}
public class Address
{
    ...
    public virtual Employee Employee { get; set; }
}

这按原样表示业务域。地址属于雇员,而雇员属于地址。

如果出于某些原因我们确实想限制此限制,则应该进行protected修改,但仍将引用保留在C#

2)使用inverse="true"。仅当我们同时映射了两侧(如上)时,才可以使用它,这将导致更多“预期和优化”的INSERT和UPDATE脚本。

在这里阅读更多:

inverse =“ true”示例和 mkyong的解释

3)几乎在任何地方都使用批量获取映射。这样可以避免在查询过程中出现1 + N个问题。阅读更多:

有关批量提取的一些细节

4)如果一个对象(in our case Employee)root 另一个对象 没有它就没有多大意义) -使用级联。阅读更多:

nhibernate-通过更新父级创建子级,还是显式创建?

映射摘要中的规则2、3、4:

<class name="Employee" ... batch-size="25">
  ...
  <bag name="Addresses"
       lazy="true" 
       inverse="true" 
       batch-size="25" 
       cascade="all-delete-orphan" >
    // wrong! This columns is the same as for many-to-one
    //<key column="AddressId" />
    // it is the one column expressing the relation
    <key column="EmployeeId" />
    <one-to-many class="Address" />
  </bag>

<class name="Address" ... batch-size="25">
  ...
  <many-to-one not-null="true" name="Employee" column="EmployeeID" />

3)如果我们使用inverse="true,别忘了分配关系的双方 (在创建过程中最关键)

原因是:

我们指示NHibernate-另一边
_(Address)_负责持久关系。但是要正确执行此操作,Address需要参考Employee-才能将其ID保留在“地址”表的列中。

因此,这应该是创建新地址的标准代码

Employee employee = ... // load or create new
Address address = new Address 
{
    ...
    Employee = employee, // this is important
};
Employee.Addresses.Add(address);
session.SaveOrUpdate(employee);  // cascade will trigger the rest

我们还可以介绍一些类似的方法AddAddress()来隐藏这种复杂性,但是设置双方都是很好的方法。

2020-05-19