插入后,NHibernate仍然会发布更新

时间:2012-07-13 10:27:12

标签: nhibernate fluent-nhibernate mapping

我有一个非常简单的单向映射。见下文:

    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

5 个答案:

答案 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] - 一对多需要可以为空的外键
  •   

Release notesJIRA issue

修改此外,您指向的帖子的答案是修复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)

尝试在映射上设置inversetrue并在代码中指定关系。

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",则这是该选择的结果。你无法双管齐下。