HNibernate 1 对多关系 仅使用外键 Id 的流畅 Niberate
我想在 NHibernate 中建立一对多关系,其中 Child 表只能访问它的parentsId。或者数据库中的外键。
我已尝试以下设置:
public class ParentTable
{
public ParentTable()
{
_childRecords = new List<ChildTable>();
}
public virtual int ParentId { get; set; }
private IList<ChildTable> _childRecords;
public virtual IEnumerable<ChildTable> ChildRecords
{
get { return _childRecords; }
}
public void AddChildTable(string value)
{
_childRecords.Add(new ChildTable{ StringField = value });
}
}
public class ChildTable
{
public virtual int ChildTableId { get; set; }
public virtual string StringField { get; set; }
public virtual int ParentId { get; set; }
}
映射:
public class ParentTableMap : ClassMap<ParentTable>
{
public ParentTableMap()
{
Not.LazyLoad();
Id(x => x.ParentId);
HasMany(x => x.ChildRecords)
.Not.LazyLoad()
.KeyColumn("ParentId").Cascade.All()
.Access.ReadOnlyPropertyThroughCamelCaseField(Prefix.Underscore);
}
}
public class ChildTableMap : ClassMap<ChildTable>
{
public ChildTableMap()
{
Not.LazyLoad();
Id(x => x.ChildTableId);
Map(x => x.StringField);
Map(x => x.ParentId).Not.Nullable();
}
}
以下测试失败,因为它试图将 0 插入 ParentId 列?
[TestFixture]
public class Tests
{
[Test]
public void SaveOrUpdate_ParentWithChildren_WillCreateParentWithChildRecordsHavingMatchingParentId()
{
int id;
using (var sessionForInsert = SessionProvider.SessionFactory.OpenSession())
{
using (var trx = sessionForInsert.BeginTransaction())
{
//Assign
var parent = new ParentTable();
parent.AddChildTable("Testing");
parent.AddChildTable("Testing2");
sessionForInsert.SaveOrUpdate(parent); // Fails here with DB constraint error
id = parent.ParentId;
}
}
using (var sessionForSelect = SessionProvider.SessionFactory.OpenSession())
{
//Action
var result = sessionForSelect.Get<ParentTable>(id);
Assert.AreEqual(id, result.ParentId);
Assert.AreEqual(id, result.ChildRecords.First().ParentId);
Assert.AreEqual(id, result.ChildRecords.Last().ParentId);
}
}
}
这就是它想要做的:
exec sp_executesql N'INSERT INTO ChildTable (StringField, ParentId) VALUES (@p0, @p1); select SCOPE_IDENTITY()',N'@p0 nvarchar,@p1 int',@p0='Testing;,@p1=0
我意识到我可以在子类中设置对父类的引用。但是,由于循环引用以及序列化和反序列化这些类时会导致的问题,我希望尽可能避免这种情况。
有人成功建立了像上面这样的一对多关系吗?
谢谢
戴夫
I'm wanting to have a 1 to many relationship in NHibernate where the Child table only has access to it's parentsId. Or the foreign key in the DB.
I've tried the following setup:
public class ParentTable
{
public ParentTable()
{
_childRecords = new List<ChildTable>();
}
public virtual int ParentId { get; set; }
private IList<ChildTable> _childRecords;
public virtual IEnumerable<ChildTable> ChildRecords
{
get { return _childRecords; }
}
public void AddChildTable(string value)
{
_childRecords.Add(new ChildTable{ StringField = value });
}
}
public class ChildTable
{
public virtual int ChildTableId { get; set; }
public virtual string StringField { get; set; }
public virtual int ParentId { get; set; }
}
Mappings:
public class ParentTableMap : ClassMap<ParentTable>
{
public ParentTableMap()
{
Not.LazyLoad();
Id(x => x.ParentId);
HasMany(x => x.ChildRecords)
.Not.LazyLoad()
.KeyColumn("ParentId").Cascade.All()
.Access.ReadOnlyPropertyThroughCamelCaseField(Prefix.Underscore);
}
}
public class ChildTableMap : ClassMap<ChildTable>
{
public ChildTableMap()
{
Not.LazyLoad();
Id(x => x.ChildTableId);
Map(x => x.StringField);
Map(x => x.ParentId).Not.Nullable();
}
}
The following test fails as it's trying to insert 0 into the ParentId column?
[TestFixture]
public class Tests
{
[Test]
public void SaveOrUpdate_ParentWithChildren_WillCreateParentWithChildRecordsHavingMatchingParentId()
{
int id;
using (var sessionForInsert = SessionProvider.SessionFactory.OpenSession())
{
using (var trx = sessionForInsert.BeginTransaction())
{
//Assign
var parent = new ParentTable();
parent.AddChildTable("Testing");
parent.AddChildTable("Testing2");
sessionForInsert.SaveOrUpdate(parent); // Fails here with DB constraint error
id = parent.ParentId;
}
}
using (var sessionForSelect = SessionProvider.SessionFactory.OpenSession())
{
//Action
var result = sessionForSelect.Get<ParentTable>(id);
Assert.AreEqual(id, result.ParentId);
Assert.AreEqual(id, result.ChildRecords.First().ParentId);
Assert.AreEqual(id, result.ChildRecords.Last().ParentId);
}
}
}
This is what it's trying to do:
exec sp_executesql N'INSERT INTO ChildTable (StringField, ParentId) VALUES (@p0, @p1); select SCOPE_IDENTITY()',N'@p0 nvarchar,@p1 int',@p0='Testing;,@p1=0
I realise I could set-up a reference to the Parent Class in the Child Class. However I'd like to avoid this if at all possible, due to circular references and the problems that will cause when serializing and de-serializing these classes.
Has anyone successfully set-up and 1 to many relationship like the above?
Thanks
Dave
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为您要么需要:
ChildTable
上的ParentId
可以为空,或者第二个选择很好。切换到 Guid.Comb 查找您的 ID。对象关系映射器可以执行的操作受到限制。具体来说,建议让 NHibernate 生成 id 而不是数据库。我认为这篇(长)博客文章详细解释了它: http: //fabiomaulo.blogspot.com/2009/02/nh210-generators-behavior-explained.html。
祝你好运!
I think you either need to:
ParentId
onChildTable
nullable, orThe second option is nice. Switch to Guid.Comb for your id's. There's a restriction on what object relational mappers can do. Specifically, it is recommended to let NHibernate generate the id's instead of the database. I think this (long) blog post explains it in detail: http://fabiomaulo.blogspot.com/2009/02/nh210-generators-behavior-explained.html.
Good luck!
问题是您试图在一个操作中插入父级及其子级。为此,NHibernate 希望插入具有 null ParentId 的子记录,然后在插入父记录后更新 ParentId。此外键约束导致此操作失败。
最好的解决方案是映射从孩子到父母的关系。您不必公开公开父级,您可以将其 ParentId 公开为 int 吗?如果需要的话。
如果这是不可接受的,您应该能够通过更改操作顺序来完成此操作。首先,我需要 ChildTable 的构造函数中的 ParentId。然后更改测试中的操作顺序即可通过。
编辑:
The problem is that you are attempting to insert a parent and its children in one operation. To do this, NHibernate wants to insert the child records with a null ParentId then update ParentId after the parent record is inserted. This foreign key constraint causes this to fail.
The best solution is to map the relationship from child to parent. You don't have to publicly expose the parent, you could just expose its ParentId as int? if desired.
If that's unacceptable, you should be able to accomplish this by changing the order of operations. First, I would require the ParentId in ChildTable's constructor. Then change the operation order in the test to get it to pass.
EDIT: