我有一个非常简单的单向映射。见下文:
public ContactMap()
{
Id(x => x.Id).GeneratedBy.Assigned();
Map(x => x.Name);
References(x => x.Device);
HasMany(x => x.Numbers)
.Not.Inverse()
.Not.KeyNullable()
.Cascade.AllDeleteOrphan()
.Not.LazyLoad()
.Fetch.Subselect();
Table("Contacts");
}
public PhoneNumberMap()
{
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.Number);
Table("ContactNumbers");
}
根据nhibernate 3及更高版本之后的post,将key设置为不可为空应该修复insert-update问题(NHibernate发出插入时外键设置为null然后更新更新的问题用于纠正价值的外键),但对我来说情况并非如此。当我将密钥设置为不可为空时,NHibernate会发出正确的插入语句
INSERT INTO ContactNumbers
(Number,
ContactId)
VALUES ('(212) 121-212' /* @p0 */,
10 /* @p1 */);
如您所见,它会插入ContactId字段,但在此之后,它仍会发出更新语句
UPDATE ContactNumbers
SET ContactId = 10 /* @p0 */
WHERE Id = 34 /* @p1 */
所以澄清问题。 NHibernate使用正确分配的外键插入Contact行,然后发出更新语句以更新冗余的外键(ContactId)。
如何摆脱这种冗余的更新声明? 感谢。
BTW,我使用的是最新版本的NHibernate和Fluent NHibernate。数据库是SQLite
答案 0 :(得分:22)
您必须将"updatable"=false
设置为密钥才能阻止更新。
public ContactMap()
{
Id(x => x.Id).GeneratedBy.Assigned();
Map(x => x.Name);
References(x => x.Device);
HasMany(x => x.Numbers)
.Not.Inverse()
.Not.KeyNullable()
.Not.KeyUpdate() // HERE IT IS
.Cascade.AllDeleteOrphan()
.Not.LazyLoad()
.Fetch.Subselect();
Table("Contacts");
}
答案 1 :(得分:4)
你不能从3.2.0 BETA开始。
在v3.2.0 BETA中,对一对多的改进将这种异常引入单向一对多关系(实际上我不确定你是否会称之为异常)。
在3.2之前,您需要设置外键以允许此类关系的空值起作用。所以我会忽略这种情况发生的事实并且随之而去。否则,您需要将其更改为完全双向的关系。
- [NH-941] - 一对多需要可以为空的外键
修改此外,您指向的帖子的答案是修复save null-save-update
而不是修复附加更新
答案 2 :(得分:3)
我不知道你是否真的可以摆脱它。
尝试使用另一个id生成器作为本机。它强制NH只插入记录以获取id。 id用于会话中的每个实体,因此以后无法进行插入。它可能会后续更新。使用hi-lo或类似的东西。
修改强>
为什么不在这种情况下使用组件?如果电话号码仅由一个号码组成,则无需单独映射电话号码。这样的事情(我不是FNH用户,所以可能是错的):
public ContactMap()
{
Id(x => x.Id).GeneratedBy.Assigned();
Map(x => x.Name);
References(x => x.Device);
HasMany(x => x.Numbers)
.Not.Inverse()
.Not.KeyNullable()
.Cascade.AllDeleteOrphan()
.Not.LazyLoad()
.Fetch.Subselect()
.Component(c =>
{
Map(x => x.Number);
})
.Table("ContactNumbers");
Table("Contacts");
}
答案 3 :(得分:3)
尝试在映射上设置inverse
到true
并在代码中指定关系。
Inverse
表示孩子负责持有父母的身份。
e.g。
var contact = new Contact();
var phoneNumber = new PhoneNumber();
phoneNumber.Contact = contact;
这样,当您为PhoneNumber记录执行插入操作时,NH可以插入ContactId而无需单独更新。
这就是我以前在NH 2中所做的事情,我认为这种行为在3中仍然有效。
答案 4 :(得分:1)
这是Trevor Pilley所说的。使用inverse="true"
。如果您选择不inverse="true"
,则这是该选择的结果。你无法双管齐下。