[英]NHibernate with mapping by code and a SQLite database: saving many-to-one parent-child entities, child gets a null foreign key
这个问题的变化已被要求,并回答了很多次,答案有很多重叠的细节。 我已经尝试过这些答案提出的许多不同的事情,但是没有一个在我的案例中有效。
我有一个带有父表和子表的SQLite数据库。 这是一个非常简单的设置。 我正在使用NHibernate 4.0.4进行代码映射而不是流畅,因为它向我建议前者是较新的并且是对后者的改进 。
实体:
public class BillingItem
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
// ... other properties
public virtual ICollection<PaymentItem> PaymentItems { get; set; }
public BillingItem()
{
PaymentItems = new List<PaymentItem>();
}
}
public class PaymentItem
{
public virtual int ID { get; set; }
public virtual BillingItem OwningBillingItem { get; set; }
// ... other properties
}
BillingItem映射:
public class BillingItemMapping : ClassMapping<BillingItem>
{
public BillingItemMapping()
{
Table("BillingItems");
Lazy(true);
Id(x => x.ID, map => map.Generator(Generators.Identity));
Set(x => x.PaymentItems, c =>
{
c.Key(k =>
{
k.Column("ID");
k.ForeignKey("BillingItemID");
});
c.Inverse(true);
c.Cascade(Cascade.None);
},
r => r.OneToMany(o => { }));
Property(x => x.Name);
// ... other properties
}
}
PaymentItem映射:
public class PaymentItemMapping : ClassMapping<PaymentItem>
{
public PaymentItemMapping()
{
Table("PaymentItems");
Lazy(true);
Id(x => x.ID, map => map.Generator(Generators.Identity));
ManyToOne(x => x.OwningBillingItem, m =>
{
m.Column("ID");
m.Update(false);
m.Insert(false);
m.Cascade(Cascade.None);
m.Fetch(FetchKind.Join);
m.NotFound(NotFoundMode.Exception);
m.Lazy(LazyRelation.Proxy);
m.ForeignKey("BillingItemID");
});
Property(x => x.DueDate, map => map.NotNullable(true));
// ... other properties.
}
}
仓库:
public void Add(BillingItem toAdd)
{
using (ISession session = Helpers.NHibernateHelper.OpenSession())
using (ITransaction tran = session.BeginTransaction())
{
session.Save(toAdd);
foreach (var pi in toAdd.PaymentItems)
{
session.Save(pi);
}
tran.Commit();
}
}
商业逻辑:
var bi = new BillingItem()
{
Name = Guid.NewGuid().ToString(),
// ... others..
};
var pi = new PaymentItem()
{
OwningBillingItem = bi,
DueDate = DateTime.Now.AddDays(3)
// ... others..
};
bi.PaymentItems.Add(pi);
var repo = new Repository();
repo.Add(bi);
正如建议这个答案 (和这个和这个和许多其他人),我已经确定设置Inverse(true)
在我的Set
中(子集) BillingItemMapping
。 我还在PaymentItem
对象中设置了我的双向引用:
OwningBillingItem = bi
和BillingItem
对象:
bi.PaymentItems.Add(pi);
我觉得我已经按照它应该的方式设置了所有其他内容,并且我根据各种其他来源的建议对许多映射设置进行了修改。 但是,我只是想不通为什么它不起作用。
问题是,我无法获取PaymentItem
记录上的外键列来保存BillingItem
的ID。 如果我将列设置为不允许空值(这应该是它的方式),我得到一个空约束异常。 如果我将其设置为允许空值(用于测试),它只是设置为null(显然)。
我究竟做错了什么?
呵呵,你的PaymentItemMapping
,正确的映射应该是这样的:
public class PaymentItemMapping : ClassMapping<PaymentItem> {
public PaymentItemMapping() {
Table("PaymentItems");
Lazy(true);
Id(x => x.ID, map => map.Generator(Generators.Identity));
ManyToOne(x => x.OwningBillingItem, m => {
//Do not map to m.Column("ID");
m.Column("BillingItemID");
// BillingItemID can be insert and update
m.Update(true);
m.Insert(true);
m.Cascade(Cascade.None);
m.Fetch(FetchKind.Join);
m.NotFound(NotFoundMode.Exception);
m.Lazy(LazyRelation.Proxy);
m.ForeignKey("BillingItemID");
});
Property(x => x.DueDate, map => map.NotNullable(true));
// ... other properties.
}
}
映射的一部分似乎是错误的,是一set
一column
// BillingItemMapping()
Set(x => x.PaymentItems, c =>
{
// this should refer to column where parent id will be found
c.Key(k =>
{
k.Column("ID");
k.ForeignKey("BillingItemID");
});
所以它应该是
c.Key(k =>
{
k.Column("BillingItemID");
});
外键只适用于sql生成器..现在可以跳过它
此外,对于每个集合,我使用级联
Set(x => x.PaymentItems, c =>
{
c.Key(k =>
{
k.Column("BillingItemID");
});
c.Inverse(true);
//c.Cascade(Cascade.None);
c.Cascade(Cascade.All);
},
有了这个,我们可以简化调用以坚持所有
using (ISession session = Helpers.NHibernateHelper.OpenSession())
using (ITransaction tran = session.BeginTransaction())
{
session.Save(toAdd);
//foreach (var pi in toAdd.PaymentItems)
//{
// session.Save(pi);
//}
tran.Commit();
}
(我们仍然需要保留两个引用parent-child / child-parent)
最后 - 当我们有级联 - 我们必须允许NHibernate完成它的工作 - INSERT和UPDATE这种关系
ManyToOne(x => x.OwningBillingItem, m =>
{
m.Column("ID");
// this is stopper - DO NOT use it
//m.Update(false);
//m.Insert(false);
因此,如果我们想要更新和插入,请不要设置Update(false)
和Insert(false)
。 这应该解决所有..
这也可以得到一些见解:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.