2012-07-13 81 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",這是選擇的結果。你不能兩面都有。