Fluent NHibernate Mapping 设置为 AllDeleteOrphan 但仍在尝试将数据库中的外键清空
当我尝试在任何具有一对多关系的表上执行 ISession.Delete 时,NHibernate 出现错误。
NHibernate正在尝试将子表中父表的外键设置为null,而不是仅仅删除子表行。
这是我的域:
public class Parent
{
public Parent()
{
_children = new List<Child>();
}
public int Id { get; set; }
public string SimpleString { get; set; }
public DateTime? SimpleDateTime { get; set; }
private IList<Child> _children;
public IEnumerable<Child> Children
{
get { return _children; }
}
public void AddChild(Child child)
{
child.Parent = this;
_children.Add(child);
}
}
public class Child
{
public int Id { get; set; }
public string SimpleString { get; set; }
public DateTime? SimpleDateTime { get; set; }
[JsonIgnore]
public Parent Parent { get; set; }
}
我已经设置了 Fluent NHibernate 映射,如下所示:
public class ParentMap : ClassMap<Parent>
{
public ParentMap()
{
Not.LazyLoad();
Id(x => x.Id);
Map(x => x.SimpleString);
Map(x => x.SimpleDateTime);
HasMany(x => x.Children)
.Not.LazyLoad()
.KeyColumn("ParentId").Cascade.AllDeleteOrphan()
.Access.ReadOnlyPropertyThroughCamelCaseField(Prefix.Underscore);
}
}
public class ChildMap : ClassMap<Child>
{
public ChildMap()
{
Not.LazyLoad();
Id(x => x.Id);
Map(x => x.SimpleString);
Map(x => x.SimpleDateTime);
References(x => x.Parent).Not.Nullable().Column("ParentId").Cascade.All().Fetch.Join();
}
}
我已经告诉 NHibernate Cascade.AllDeleteOrphan()
但它仍然尝试将 ParentId foriegn 键设置为 null 这里是测试我的设置:
public void Delete_GivenTableWithChildren_WillBeDeletedFromDB()
{
int id;
using (var createSession = MsSqlSessionProvider.SessionFactory.OpenSession())
{
var parent = new Parent();
parent.AddChild(new Child { SimpleString = "new child from UI" });
using (var trx = createSession.BeginTransaction())
{
createSession.Save(parent);
trx.Commit();
id = parent.Id;
}
}
using (var firstGetSession = MsSqlSessionProvider.SessionFactory.OpenSession())
{
var result = firstGetSession.Get<Parent>(id);
Assert.IsNotNull(result);
}
using (var deleteSession = MsSqlSessionProvider.SessionFactory.OpenSession())
{
using (var trx = deleteSession.BeginTransaction())
{
deleteSession.Delete("from " + typeof(Parent).Name + " o where o.Id = :Id", id, NHibernateUtil.Int32);
trx.Commit();
}
}
using (var session = MsSqlSessionProvider.SessionFactory.OpenSession())
{
var result = session.Get<Parent>(id);
Assert.IsNull(result);
}
}
尝试以下 SQL 后,deleteSession.Delete
行失败
exec sp_executesql N'UPDATE [Child] SET ParentId = null WHERE ParentId = @p0',N'@p0 int',@p0=5
:
NHibernate.Exceptions.GenericADOException : could not delete collection: [SaveUpdateOrCopyTesting.Parent.Children#5][SQL: UPDATE [Child] SET ParentId = null WHERE ParentId = @p0]
----> System.Data.SqlClient.SqlException : Cannot insert the value NULL into column 'ParentId', table 'SaveUpdateCopyTestingDB.dbo.Child'; column does not allow nulls. UPDATE fails.
The statement has been terminated.
有谁知道我在映射中做错了什么,或者知道阻止 NHibernate 的方法试图将外键 ID 设为空?
谢谢
戴夫
I'm getting an error with NHibernate when I try to perfrom a ISession.Delete on any table with a One to Many relationship.
NHibernate is trying to set the foreign key to the parent table in the child table to null, rather than just deleting the child table row.
Here is my domain:
public class Parent
{
public Parent()
{
_children = new List<Child>();
}
public int Id { get; set; }
public string SimpleString { get; set; }
public DateTime? SimpleDateTime { get; set; }
private IList<Child> _children;
public IEnumerable<Child> Children
{
get { return _children; }
}
public void AddChild(Child child)
{
child.Parent = this;
_children.Add(child);
}
}
public class Child
{
public int Id { get; set; }
public string SimpleString { get; set; }
public DateTime? SimpleDateTime { get; set; }
[JsonIgnore]
public Parent Parent { get; set; }
}
I have set-up the Fluent NHibernate mappings as follows:
public class ParentMap : ClassMap<Parent>
{
public ParentMap()
{
Not.LazyLoad();
Id(x => x.Id);
Map(x => x.SimpleString);
Map(x => x.SimpleDateTime);
HasMany(x => x.Children)
.Not.LazyLoad()
.KeyColumn("ParentId").Cascade.AllDeleteOrphan()
.Access.ReadOnlyPropertyThroughCamelCaseField(Prefix.Underscore);
}
}
public class ChildMap : ClassMap<Child>
{
public ChildMap()
{
Not.LazyLoad();
Id(x => x.Id);
Map(x => x.SimpleString);
Map(x => x.SimpleDateTime);
References(x => x.Parent).Not.Nullable().Column("ParentId").Cascade.All().Fetch.Join();
}
}
I've told NHibernate to Cascade.AllDeleteOrphan()
but it's still trying to set the ParentId foriegn key to null here is the test I setup:
public void Delete_GivenTableWithChildren_WillBeDeletedFromDB()
{
int id;
using (var createSession = MsSqlSessionProvider.SessionFactory.OpenSession())
{
var parent = new Parent();
parent.AddChild(new Child { SimpleString = "new child from UI" });
using (var trx = createSession.BeginTransaction())
{
createSession.Save(parent);
trx.Commit();
id = parent.Id;
}
}
using (var firstGetSession = MsSqlSessionProvider.SessionFactory.OpenSession())
{
var result = firstGetSession.Get<Parent>(id);
Assert.IsNotNull(result);
}
using (var deleteSession = MsSqlSessionProvider.SessionFactory.OpenSession())
{
using (var trx = deleteSession.BeginTransaction())
{
deleteSession.Delete("from " + typeof(Parent).Name + " o where o.Id = :Id", id, NHibernateUtil.Int32);
trx.Commit();
}
}
using (var session = MsSqlSessionProvider.SessionFactory.OpenSession())
{
var result = session.Get<Parent>(id);
Assert.IsNull(result);
}
}
Which is failing on the deleteSession.Delete
line after attempting the following SQL:
exec sp_executesql N'UPDATE [Child] SET ParentId = null WHERE ParentId = @p0',N'@p0 int',@p0=5
with:
NHibernate.Exceptions.GenericADOException : could not delete collection: [SaveUpdateOrCopyTesting.Parent.Children#5][SQL: UPDATE [Child] SET ParentId = null WHERE ParentId = @p0]
----> System.Data.SqlClient.SqlException : Cannot insert the value NULL into column 'ParentId', table 'SaveUpdateCopyTestingDB.dbo.Child'; column does not allow nulls. UPDATE fails.
The statement has been terminated.
Does anyone know what I've done wrong in my mappings, or know of a way to stop NHibernate from attempting to null the foreign key id?
Thanks
Dave
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
尝试在 ParentMap 的 HasMany 上设置 .Inverse() ,所以它看起来像:
Try setting .Inverse() on the ParentMap's HasMany, so it looks like:
如果用 HQL 删除,我不确定级联是否有效。
试试这个:
遗憾的是你没有延迟加载。
Load
不需要从数据库读取实体,它只是在内存中创建一个代理。I'm not sure if cascade works if you delete with HQL.
Try this:
It's a pity that you don't have lazy loading.
Load
would not need the entity to be read from the database, it would just create a proxy in memory.