nhibernate 4.0 中的双向关系
Bi-directional relationship in nhibernate 4.0
我有一段代码在 NHibernate 3.1 上运行良好,但在 NHibernate 4.0 上运行不正常
所以,这是class关系
public class Employee : BaseEntity
{
...
public Department Dept { get; set; }
}
public class Department : BaseEntity
{
...
public IList<Employee> Employees { get; set; }
}
对于映射我们有这个
DepartmentMap : ClassMap<Department>
{
Table("....");
HasMany(x => x.Employees).KeyColumn("DeptId").Not.KeyNullable();
}
EmployeeMap : ClassMap<Employee>
{
Reference(x => x.Dept).Column("DeptId");
}
当我添加这样的员工时
var dept = session.Load<Department>(deptId);
newEmployee.Dept = dept;
session.Save(newEmployee);
但是它抛出一个错误:
NHibernate.PropertyValueException: not-null property references a null
or transient value
我看到我必须通过两种方式添加关系,所以我将其修改为
var dept = session.Load<Department>(deptId);
newEmployee.Dept = dept;
dept.Employees.Add(newEmployee);
session.Save(newEmployee);
但是现在我有这个错误:
NHibernate.PropertyValueException: Error dehydrating property value
for... System.IndexOutOfRangeException: Invalid index 7 for this
SqlParameterCollection with Count=7.
所以,我想知道如何修复它,以及在哪里可以阅读 NHibernate 中有关双向更改的信息
第一期-双向映射
我们应该始终分配关系的双方。好吧,总是?!? 这是推荐的好做法。
但是 以防万一,我们想使用 .Load()
来检索 parent
(部门) -我们应该 而不是 需要分配 parent.Chidren.Add()
。
Load()
是获取 "fake"(代理)实例的聪明方法,仅由该实体的 ID 表示 (足以创建正确的 INSERT 语句)
所以,在这种情况下我们应该避免 dept.Employees.Add(newEmployee);
- 我们根本不需要加载 Department
// existing parent - but NHibernate just creates a proxy with expected ID
var dept = session.Load<Department>(deptId);
// child Employee is provided with parent reference - it is enough
newEmployee.Dept = dept;
// this will not help, just will execute SELECT - no benefit
// dept.Employees.Add(newEmployee);
// save and it should work
session.Save(newEmployee);
第二个(真正的)问题 - 双映射
虽然在问题代码片段中看不到,但我敢打赌,Employee 实际上有这个 def 和映射
public class Employee : BaseEntity
{
...
// reference
public virtual Department Dept { get; set; }
// reference_ID also mapped as integer
public virtual int? DeptId { get; set; }
}
EmployeeMap : ClassMap<Employee>
{
Reference(x => x.Dept).Column("DeptId");
Map(x => x.DeptId)
// with .Not.Nullable() by code or convention
;
}
所以 - 我们在 C# 中有两个属性属于一个 SQL 列。我会说,这绝对没问题,但我们必须确保稍微调整一下。整数应该可以为空并且必须是只读的
EmployeeMap : ClassMap<Employee>
{
Reference(x => x.Dept).Column("DeptId");
Map(x => x.DeptId)
.Nullable()
.Insert(false)
.Update(false); // as far as I rememeber syntax to replicate
// <property name="DeptId" insert="false" update="false" not-null="false />
}
所以发生了什么事?两种异常情况是什么?
NHibernate.PropertyValueException: not-null property references a null or transient value
上述问题意味着 NHibernate 期望 属性 DeptId 也被提供
NHibernate.PropertyValueException: Error dehydrating property value for... System.IndexOutOfRangeException: Invalid index 7 for this SqlParameterCollection with Count=7.
这种问题通常与双重映射有关——两个属性到一个列。通常是因为引用和引用 ID 被映射到一列...
即使问题不直接与 int? DeptId
- 我希望这能给你足够的信息来揭示真正的罪魁祸首。
我找到了问题的解决方法:
解决该问题的方法是将 Inverse 添加到父文件的映射中。
因此,Department 的映射将是:
DepartmentMap : ClassMap<Department>
{
Table("....");
HasMany(x => x.Employees).KeyColumn("DeptId").Inverse().Not.KeyNullable();
}
我有一段代码在 NHibernate 3.1 上运行良好,但在 NHibernate 4.0 上运行不正常
所以,这是class关系
public class Employee : BaseEntity
{
...
public Department Dept { get; set; }
}
public class Department : BaseEntity
{
...
public IList<Employee> Employees { get; set; }
}
对于映射我们有这个
DepartmentMap : ClassMap<Department>
{
Table("....");
HasMany(x => x.Employees).KeyColumn("DeptId").Not.KeyNullable();
}
EmployeeMap : ClassMap<Employee>
{
Reference(x => x.Dept).Column("DeptId");
}
当我添加这样的员工时
var dept = session.Load<Department>(deptId);
newEmployee.Dept = dept;
session.Save(newEmployee);
但是它抛出一个错误:
NHibernate.PropertyValueException: not-null property references a null or transient value
我看到我必须通过两种方式添加关系,所以我将其修改为
var dept = session.Load<Department>(deptId);
newEmployee.Dept = dept;
dept.Employees.Add(newEmployee);
session.Save(newEmployee);
但是现在我有这个错误:
NHibernate.PropertyValueException: Error dehydrating property value for... System.IndexOutOfRangeException: Invalid index 7 for this SqlParameterCollection with Count=7.
所以,我想知道如何修复它,以及在哪里可以阅读 NHibernate 中有关双向更改的信息
第一期-双向映射
我们应该始终分配关系的双方。好吧,总是?!? 这是推荐的好做法。
但是 以防万一,我们想使用 .Load()
来检索 parent
(部门) -我们应该 而不是 需要分配 parent.Chidren.Add()
。
Load()
是获取 "fake"(代理)实例的聪明方法,仅由该实体的 ID 表示 (足以创建正确的 INSERT 语句)
所以,在这种情况下我们应该避免 dept.Employees.Add(newEmployee);
- 我们根本不需要加载 Department
// existing parent - but NHibernate just creates a proxy with expected ID
var dept = session.Load<Department>(deptId);
// child Employee is provided with parent reference - it is enough
newEmployee.Dept = dept;
// this will not help, just will execute SELECT - no benefit
// dept.Employees.Add(newEmployee);
// save and it should work
session.Save(newEmployee);
第二个(真正的)问题 - 双映射
虽然在问题代码片段中看不到,但我敢打赌,Employee 实际上有这个 def 和映射
public class Employee : BaseEntity
{
...
// reference
public virtual Department Dept { get; set; }
// reference_ID also mapped as integer
public virtual int? DeptId { get; set; }
}
EmployeeMap : ClassMap<Employee>
{
Reference(x => x.Dept).Column("DeptId");
Map(x => x.DeptId)
// with .Not.Nullable() by code or convention
;
}
所以 - 我们在 C# 中有两个属性属于一个 SQL 列。我会说,这绝对没问题,但我们必须确保稍微调整一下。整数应该可以为空并且必须是只读的
EmployeeMap : ClassMap<Employee>
{
Reference(x => x.Dept).Column("DeptId");
Map(x => x.DeptId)
.Nullable()
.Insert(false)
.Update(false); // as far as I rememeber syntax to replicate
// <property name="DeptId" insert="false" update="false" not-null="false />
}
所以发生了什么事?两种异常情况是什么?
NHibernate.PropertyValueException: not-null property references a null or transient value
上述问题意味着 NHibernate 期望 属性 DeptId 也被提供
NHibernate.PropertyValueException: Error dehydrating property value for... System.IndexOutOfRangeException: Invalid index 7 for this SqlParameterCollection with Count=7.
这种问题通常与双重映射有关——两个属性到一个列。通常是因为引用和引用 ID 被映射到一列...
即使问题不直接与 int? DeptId
- 我希望这能给你足够的信息来揭示真正的罪魁祸首。
我找到了问题的解决方法: 解决该问题的方法是将 Inverse 添加到父文件的映射中。 因此,Department 的映射将是:
DepartmentMap : ClassMap<Department>
{
Table("....");
HasMany(x => x.Employees).KeyColumn("DeptId").Inverse().Not.KeyNullable();
}