使用NHibernate进行一对多映射的最小和正确方法 [英] Minimal and correct way to map one-to-many with NHibernate

查看:69
本文介绍了使用NHibernate进行一对多映射的最小和正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是NHibernate和C#的新手,请保持谦虚!

I am new to NHibernate and C#, so please be gentle!

我有以下两个NHibernate实体:

I have the following two NHibernate entities:

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
}

,并且它们在EmployeeAddress 之间具有one-to-many关系(每个 员工可以在其记录中包含多个地址).方便地忽略 一个以上的员工可能居住在同一地址的事实.

and they have a one-to-many relationship from Employee to Address (each employee can have multiple addresses in their record). Conveniently ignoring the fact that more than one employee may reside at the same address.

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

I understand this from the perspective of objects in memory (the NHibernate entities). What I am struggling with are the mapping files (and I am taking an easy example here). This is what I have come up with so far:

// 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中的Address,反之亦然...
  1. Is this correct?
  2. If not, it seems like what I am missing here is a field in the Address entity that is a reference to the corresponding Employee entity. But if so, then I can't understand why this is required: I don't need to fetch an Address from an Employee, only the other way round...

推荐答案

只有几个提示,总结了我在使用NHibernate时发现的最合适的标准.

Just few hints, summarizing the most suitable standards I found out when working with NHibernate.

1)如果在持久性(数据库列)中存在双向引用,请以C#代码双向表示>也是如此.

1) If there is a bi-directional reference in persitence (DB column), express it in C# code bi-directional as well.

换句话说,如果 child 引用了 parent ,则 parent 应当引用了 child .

Other words, if a child has reference to parent, parent should have reference to child.

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

这表示业务领域.地址属于雇员,而雇员属于地址.

This represents Business Domain as is. Address belongs to Employee and Employee belongs to Address.

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

If we for some reasons really want to restrict that, we should rather protected modifier, but still keep the reference in C#

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

2) Use inverse="true". This could be used only if we mapped both sides (as above), and will lead to more "expected and optimized" INSERT and UPDATE scritps

在此处了解更多信息

inverse ="true"的示例和说明通过mkyong

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

3) Use batch fetching mapping almost everwhere. That will avoid 1 + N issues during querying. Read more:

有关批量提取的一些详细信息

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

4) In case, that one object (in our case Employee) is root (the other does not make so much sense without it) - use cascading. Read more:

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

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

Rules 2,3,4 in a mapping snippets:

<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,请不要忘记分配关系的两侧(在创建过程中最关键)

3) if we use inverse="true do not forget to assign both sides of relation (mostly critical during creation)

原因是:

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

we instruct NHibernate - the other side (Address) is responsible for persisting relation. But to do that properly, that Address needs to have reference to Employee - to be able to persist its ID into its column in Address table.

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

So this should be the standard code to create new Address

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()的方法,该方法将隐藏这种复杂性,但是设置双方都是很好的选择.

We can also introduce some method like AddAddress() which will hide this complexity, but setting both sides is a good prectice.

这篇关于使用NHibernate进行一对多映射的最小和正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆