Ken*_*nic 6 nhibernate foreign-keys fluent-nhibernate
我有一个问题,应该是一个相当简单的(我认为)NHibernate用例.
我有一个经典的Parent和Child实体,如下所示:
public class Parent
{
public virtual int ParentId { get; set; }
public virtual string Name { get; set; }
public virtual IList<Child> Children { get; set; }
}
public class Child
{
public virtual int ChildId { get; set; }
public virtual Parent Parent { get; set; }
public virtual string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
映射如下:
public class ParentMap : ClassMap<Parent>
{
public ParentMap()
{
Id(x => x.ParentId).GeneratedBy.Native();
Map(x => x.Name);
HasMany(x => x.Children).KeyColumn("ParentId").Cascade.SaveUpdate();
}
}
public class ChildMap : ClassMap<Child>
{
public ChildMap()
{
Id(x => x.ChildId).GeneratedBy.Native();
Map(x => x.Name);
References(x => x.Parent).Column("ParentId").ReadOnly().Not.Nullable();
}
}
Run Code Online (Sandbox Code Playgroud)
最后,我有一个简单的测试:
[Test]
public void Test_save_family()
{
var parent = new Parent();
var child = new Child {Parent = parent};
parent.Children = new List<Child>{child};
SessionManager.WithSession(
session =>
{
session.Save(parent);
session.Flush();
});
}
Run Code Online (Sandbox Code Playgroud)
使用System.Data.SqlClient.SqlException测试失败:无法将值NULL插入"ParentId"列.这是正确的,因为列是不可为空的,但为什么插入null?
如果我删除了null约束,则保存起作用,因为NHibernate首先插入父节点,然后插入子节点,然后更新子记录上的ParentId列,如此输出所示:
NHibernate: INSERT INTO [Parent] (Name) VALUES (@p0); select SCOPE_IDENTITY();@p0 = NULL
NHibernate: INSERT INTO [Child] (Name) VALUES (@p0); select SCOPE_IDENTITY();@p0 = NULL
NHibernate: UPDATE [Child] SET ParentId = @p0 WHERE ChildId = @p1;@p0 = 2, @p1 = 1
Run Code Online (Sandbox Code Playgroud)
这对我来说似乎很奇怪,因为在几乎所有情况下,这种外键列都被声明为非可空,因此必须在插入时提供外键.那么为什么NHibernate没有在子行的初始插入上设置外键以及如何解决这个问题呢?
您的映射存在一些问题......您有双向关系,NHibernate需要知道更新它的方法.在OO世界中,引用只有一种方式,NHibernate无法知道Parent-> Children与Child-> Parent是相同的FK.现在你将Child-> Parent设置为ReadOnly().这告诉NHibernate不要更新这个属性.因此它尝试插入Child(使用null父级),然后从Parent侧更新FK.如果您的FK上有非空约束,则此方法无效.通常的映射方法是在父端使用Inverse = true,让孩子担心持久性.(这是您在OO模型中的工作,以确保Parent-> Children集合包含与Child-> Parent关系集相同的一组引用.)
public class ParentMap : ClassMap<Parent>
{
public ParentMap()
{
Id(x => x.ParentId).GeneratedBy.Native();
Map(x => x.Name);
HasMany(x => x.Children).KeyColumn("ParentId").Inverse().Cascade.SaveUpdate();
}
}
public class ChildMap : ClassMap<Child>
{
public ChildMap()
{
Id(x => x.ChildId).GeneratedBy.Native();
Map(x => x.Name);
References(x => x.Parent).Column("ParentId").Not.Nullable(); // Removed ReadOnly()
}
}
Run Code Online (Sandbox Code Playgroud)
保存时发送到数据库的SQL语句现在是:
INSERT INTO [Parent]
(Name)
VALUES ('P1' /* @p0 */)
select SCOPE_IDENTITY()
INSERT INTO [Child]
(Name,
ParentId)
VALUES ('C1' /* @p0 */,
1 /* @p1 */)
select SCOPE_IDENTITY()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5489 次 |
| 最近记录: |