11

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

    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及更高版本之后的这篇文章,将键设置为不可为空应该可以解决插入更新问题(当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 插入具有正确分配外键的联系人行,然后发出更新语句来更新冗余的外键(ContactId)。

我怎样才能摆脱这个多余的更新语句?谢谢。

顺便说一句,我正在使用最新版本的 NHibernate 和 Fluent NHibernate。数据库是 SQLite

4

5 回答 5

25

您必须设置"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");
}
于 2012-07-20T08:55:10.637 回答
4

你不能从 3.2.0 BETA 开始。

在 v3.2.0 BETA 中,对一对多的改进将这种异常引入了单向一对多关系(实际上我不确定异常是否是你所说的)。

在 3.2 之前,您需要设置外键以允许空值才能使这种类型的关系起作用。因此,我会忽略发生这种情况的事实,并顺其自然。否则,您需要将其更改为完全双向的关系。

  • [NH-941] - 一对多需要可空外键

发行说明JIRA 问题

编辑您指向的帖子的答案也是修复save null-save-update而不是修复附加更新

于 2012-07-13T11:54:49.757 回答
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");
}
于 2012-07-13T11:54:34.097 回答
3

尝试在映射上设置为并在代码中分配关系inversetrue

Inverse表示孩子负责持有父母的ID。

例如

var contact = new Contact();
var phoneNumber = new PhoneNumber();
phoneNumber.Contact = contact;

这样,当您插入 PhoneNumber 记录时,NH 可以插入 ContactId 而无需单独更新。

这就是我以前在 NH 2 中所做的事情,我认为这种行为在 3 中仍然有效。

于 2012-07-13T13:13:22.413 回答
1

这是特雷弗·皮利所说的。使用inverse="true". 如果您选择不拥有inverse="true",这就是该选择的结果。你不能两全其美。

于 2012-07-17T12:49:43.877 回答