2012-07-13 82 views
8

我有一个非常简单的单向映射。见下图:插入后NHibernate仍然会更新

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"); 
    } 

根据这一post NHibernate的3及以上后,设定键为非null应该修复插件更新的问题(这个问题时,NHibernate的问题与外键设置为空,那么插入更新以更新外键以更正值),但这不适用于我。当我设定键不可为空,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)。

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

顺便说一句,我使用的是最新版本的NHibernate和流利的NHibernate的。该数据库是SQLite的

回答

20

您必须将"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

当所有的希望都消失了,你来了:D。简单,清晰,完美的作品,它甚至用单一的删除替换了更新/删除操作,该死的,你不知道我是多么的感激,这是很多人都不知道的重要问题,谢谢hazzik – Davita 2012-07-20 09:03:07

+1

是的,我们应该更新我们的文档,但它是一个巨大而无聊的工作:( – hazzik 2012-07-20 09:16:55

+1

我明白,感谢上帝,我们有:-) – Davita 2012-07-20 09:24:33

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"); 
} 
+0

对不起,我无法理解你的意思。你能否详细说明一下? :) – Davita 2012-07-13 23:06:35

+0

我把id代更改为HiLo,但它没有帮助。 – Davita 2012-07-15 13:14:56

+0

组件在这里不起作用,它与Numbers有一对多的关系。 – Davita 2012-07-19 12:04:08

4

你不能为3.2.0测试版的。

在V3.2.0 BETA介绍了这个反常现象单向一个一对多的关系的改良效果一到多(其实我不知道,如果是anormaly你把这个叫做什么)。

3.2之前,你需要设置外键,以便为这种关系的零点工作。所以我会忽略这种情况发生的事实,并随之发生。否则,您需要将其更改为完全双向关系。

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

Release notesJIRA issue

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

+0

该死的,Nhibernate支持单向关联很糟糕。如果没有什么好的话,我会等待其他答案并接受你的答案。在此期间,我将首先检查EF +代码:( – Davita 2012-07-13 15:40:47

3

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

Inverse意味着孩子负责持有家长的身份证件。

例如

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

这样,当您为PhoneNumber记录插入时,NH可以插入ContactId而不必执行单独的更新。

这就是我以前在NH 2做,我将承担行为仍然工作在3

+0

我不想做相反的事情,这就是整个想法,我希望Contact负责数字持久性 – Davita 2012-07-13 15:26:46

1

这是什么特雷弗Pilley说的一样。使用inverse="true"。如果您选择不具有inverse="true",这是选择的结果。你不能两面都有。