2013-08-27 68 views
1

我有一個簡單的多對多關係使用流利NHibernate,它工作得很好。如何避免流利NHibernate多對多關係內的子更新?

這是我的第一類映射:

public LobMapping() 
    { 
     ... 
     HasManyToMany(x => x.Commodities) 
      .Table("PPBSYS.LOB_COMMODITY") 
      .ParentKeyColumn("LOB_ID") 
      .ChildKeyColumn("COMMODITY_ID") 
      .Cascade.SaveUpdate() 
      .LazyLoad(); 
     ... 
    } 

這裏是我的第二類映射:

public CommodityMapping() 
    { 
     ... 
     HasManyToMany(x => x.Lobs) 
      .Table("PPBSYS.LOB_COMMODITY") 
      .ParentKeyColumn("COMMODITY_ID") 
      .ChildKeyColumn("LOB_ID") 
      .Inverse() 
      .Cascade.All() 
      .LazyLoad(); 
     ... 
    } 

最後,我LOB對象具有商品的列表:

public class Lob 
{ 
    ... 
    public virtual IEnumerable<Commodity> Commodities { get; set; } 
    ... 
} 

但是我不滿意這個事實,我必須參考Lob類中的整個商品。我真的想這樣做:

var lob = new Lob(); 
lob.Commodities = new [] { new Commodity { CommodityId = 1 }}; 
repository.SaveLob(lob); 

但是,如果我運行上面的代碼,NHibernate的會嘗試更新列商品表設置爲null與ID = 1

商品所以其實我必須把整個對象,節省了高球前:

var lob = new Lob(); 
lob.Commodities = new [] { repostitory.GetCommodit(1) }; 
repository.SaveLob(lob); 

知道商品存在,因爲用戶只選擇了他們。

可以完成我的任務嗎?

+0

你不能給它一個完整的實體,只是ID進行着,當然它將嘗試刪除其中的所有內容,您可以嘗試(不知道它是否會起作用):使用您在許多「COMMODITY_ID」中設置的相同名稱映射商品的keyColumn,並嘗試僅設置該列並保存,這對於我來說簡單的HasMany –

+0

實際上,Commodity的主鍵是CommodityId(與NN關係相同)。 – gustavodidomenico

回答

3

我假設您的存儲庫正在調用session.Get<T>(id)。還有session.Load<T>(id)

lob.Commodities = new [] { session.Load<Commodity>(1) }; 

NHibernate documentation on Load() ...

如果類的映射使用了代理服務器,負載()返回一個對象,它是一個未初始化的代理,並不實際訪問數據庫,直到你調用一個對象的方法。如果您希望在不實際從數據庫加載對象的情況下創建關聯,則此行爲非常有用。

+0

這真的很有希望。讓我檢查一下。 – gustavodidomenico

+0

它像一個魅力。請注意,實體必須可用於「延遲加載」(虛擬成員和映射)。 – gustavodidomenico

0

Daniel的答案聽起來很有希望,讓我知道如果在保存代理將不會擊中數據庫來填充實體的所有屬性。

另一個答案會有點用力NHibernate的,我測試了它和它的工作, 工作代碼:

public class Com 
{ 
    public virtual Guid ID { get; set; } 
    public virtual string Name { get; set; } 

    public virtual IList<Lob> Lobs { get; set; } 
} 

public class Lob 
{ 
    public virtual Guid ID { get; set; } 
    public virtual string Name { get; set; } 

    public virtual IList<Com> Coms { get; set; } 
} 

class LobMap : ClassMap<Lob> 
{ 
    public LobMap() 
    { 
     Id(x => x.ID).GeneratedBy.GuidComb(); 

     Map(x => x.Name); 

     HasManyToMany(x => x.Coms) 
     .Table("LOB_COM") 
     .ParentKeyColumn("LOB_ID") 
     .ChildKeyColumn("COM_ID") 
     .Cascade.SaveUpdate() 
     .LazyLoad(); 
    } 
} 

class ComMap : ClassMap<Com> 
{ 
    public ComMap() 
    { 
     Id(x => x.ID).GeneratedBy.GuidComb(); 

     Map(x => x.Name); 

     HasManyToMany(x => x.Lobs) 
     .Table("LOB_COM") 
     .ParentKeyColumn("COM_ID") 
     .ChildKeyColumn("LOB_ID") 
     .Inverse() 
     .Cascade.All() 
     .LazyLoad(); 
    } 
} 

現在 - 我設置一個虛擬實體模擬連接表並將其映射:

public class ComLobConnection 
{ 
    public virtual Guid ComID { get; set; } 
    public virtual Guid LobID { get; set; } 
} 

public class ComLobConnectionMap : ClassMap<ComLobConnection> 
{ 
    public ComLobConnectionMap() 
    { 
     Table("LOB_COM"); 

     Id(); 

     Map(x => x.ComID,"COM_ID"); 
     Map(x => x.LobID,"LOB_ID"); 
    } 
} 

注意到,我映射到完全相同的字段和表爲多對多,沒有ID設置(這是空ID()調用)

現在剩下的就是保存一個ComLobConnection,它將被添加到Com.Lobs和Lob中。COMS

節省了一些測試的COM,吊球

 var testCom = new Com() { Name = "TestCom" }; 
     var testLob = new Lob() { Name = "TestLob" }; 
     session.SaveOrUpdate(testCom); 
     session.SaveOrUpdate(testLob); 

後保存 - 把自己的ID和保存的連接測試

 var testConnection = new ComLobConnection() 
     { 
      ComID = Guid.Parse("D3559F53-8871-45E9-901D-A22800806567"), 
      LobID = Guid.Parse("D372D430-2E61-44F2-BA89-A228008065F1") 
     }; 
     session.SaveOrUpdate(testConnection); 

這迫使在多對多表的新紀錄,而當工作同時獲得Lob和Com。

我不推薦這:),它只是感興趣,如果它可以完成,它可以。 通過這種方式,您將不會擊中數據庫加載Coms或Lobs,您知道存在以保存它們的連接。

希望的load()不會碰到DB也太:)

編輯:可以與任何類型的ID的

+0

謝謝你的努力。我會嘗試丹尼爾的回答,看看數據庫是否沒有抱怨。 – gustavodidomenico

相關問題