C# 使用 NHibernate 映射一对多的最小且正确的方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29985158/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Minimal and correct way to map one-to-many with NHibernate
提问by markvgti
I am new to NHibernate and C#, so please be gentle!
我是 NHibernate 和 C# 的新手,所以请保持温和!
I have the following two NHibernate entities:
我有以下两个 NHibernate 实体:
Employee
{
private long _id;
private String _name;
private String _empNumber;
private IList<Address> _addresses;
//Properties...
}
and
和
Address
{
private long _id;
private String _addrLine1;
private String _addrLine2;
private String _city;
private String _country;
private String _postalCode;
//Properties
}
and they have a one-to-manyrelationship from Employeeto 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.
并且他们有one-to-many从Employee到的关系Address(每个员工的记录中可以有多个地址)。方便地忽略多个员工可能居住在同一地址的事实。
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:
我是从内存中的对象(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>
and
和
// 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>
- Is this correct?
- If not, it seems like what I am missing here is a field in the
Addressentity that is a reference to the correspondingEmployeeentity. But if so, then I can't understand why this is required: I don't need to fetch anAddressfrom anEmployee, only the other way round...
- 这样对吗?
- 如果没有,似乎我在这里缺少的是
Address实体中的一个字段,它是对相应Employee实体的引用。但如果是这样,那么我无法理解为什么需要这样做:我不需要Address从 an 中获取anEmployee,只需要反过来 ......
采纳答案by Radim K?hler
Just few hints, summarizing the most suitable standards I found out when working with NHibernate.
只是一些提示,总结了我在使用 NHibernate 时发现的最合适的标准。
1) If there is a bi-directionalreference in persitence (DB column), express it in C#code bi-directionalas well.
1)如果持久性(DB列)中有双向引用,也用代码双向表达。C#
Other words, if a childhas reference to parent, parentshould have reference to child.
换句话说,如果孩子有对parent 的引用,parent应该有对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.
这代表业务领域。地址属于雇员,雇员属于地址。
If we for some reasons really want to restrict that, we should rather
protectedmodifier, but still keep the reference inC#
如果我们出于某些原因真的想限制它,我们应该
protected修改,但仍将引用保留在C#
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
2)使用inverse="true"。这只能在我们映射双方(如上)时使用,并且会导致更多“预期和优化”的 INSERT 和 UPDATE 脚本
Read more here:
在此处阅读更多信息:
inverse = “true” example and explanationby mkyong
inverse = “true” 示例和解释由 mkyong
3) Use batch fetching mapping almost everwhere. That will avoid 1 + N issues during querying. Read more:
3) 几乎在任何地方都使用批量获取映射。这将在查询期间避免 1 + N 问题。阅读更多:
few details about batch fetching
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:
4)如果一个对象(in our case Employee)是root(没有它另一个没有那么多意义)- 使用级联。阅读更多:
nhibernate - Create child by updating parent, or create explicitly?
nhibernate - 通过更新父级来创建子级,还是显式创建?
Rules 2,3,4 in a mapping snippets:
映射片段中的规则 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) if we use inverse="truedo not forget to assign both sides of relation (mostly critical during creation)
3)如果我们使用inverse="true不要忘记分配关系的双方(在创建期间主要是关键)
The reason is:
原因是:
we instruct NHibernate - the other side (
Address)is responsible for persisting relation. But to do that properly, thatAddressneeds to have reference toEmployee- to be able to persist its ID into its column in Address table.
我们指示 NHibernate - 另一方(
Address)负责持久化关系。但是要正确地做到这一点,Address需要引用Employee- 以便能够将其 ID 保存到地址表中的列中。
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
We can also introduce some method like AddAddress()which will hide this complexity, but setting both sides is a good prectice.
我们也可以引入一些方法AddAddress()来隐藏这种复杂性,但设置两边是一个很好的方法。
回答by Najera
You should add the cascade all-delete-orphanin the one-to-manyrelation, if you delete the Employeethe address will be deleted too.
您应该all-delete-orphan在one-to-many关系中添加级联,如果删除Employee该地址也将被删除。
If you don't need Employeereference create a inverse=falserelation like this: here
如果您不需要Employee参考创建这样的inverse=false关系:here

