6

我在尋找添加兩個實體之間的關聯,並具有一個可設定的ID爲外鍵的方式。我已經搜索了以前的帖子,但最接近的我可以找到一個建議。加載協會 - 這不是我所希望的。我知道這可以在實體框架中使用.HasForeignKey綁定完成,但我似乎無法找到在Fluent NHibernate中執行此操作的方法。功能NHibernate - 映射一個外鍵的屬性

以兩個例子實體:

public class Ticket 
{ 
    public virtual int Id { get; set; } 
    public virtual string Title { get; set; } 
    public virtual string ServiceId { get; set; } 
    public virtual Service Service { get; set; } 
} 

public class Service 
{ 
    public virtual string Id { get; set; } 
} 

我希望能夠創造票務的新實例,並使用以下手段服務分配給它(假設相關服務表中已經存在):

Ticket ticket = new Ticket() { 
    Title = "Problem with MS Word", 
    ServiceId = "Microsoft Word 2012" 
}; 

我不想做的是以下幾點:

Ticket ticket = new Ticket() { 
    Title = "Problem with MS Word", 
    Service = Session.Load<Service>("Microsoft Word 2012") 
}; 

我確實有這個理由,正如我曾經說過的,這可以在實體框架中完成,但是我真的很難理解如何在Fluent NHibernate中實現同樣的事情。我的映射目前看起來像這樣:

public class TicketMapping : ClassMap<Ticket> 
{ 
    public TicketMapping() 
    { 
     Id(m => m.Id); 
     Map(m => m.Title).Column("Title"); 
     Map(m => m.ServiceId).Column("ServiceId"); 
     HasOne(m => m.Service).ForeignKey("ServiceId"); 

     Schema("dbo"); 
     Table("Tickets"); 
    } 
} 

public class ServiceMapping : ClassMap<Service> 
{ 
    public ServiceMapping() 
    { 
     Id(m => m.Id); 

     Schema("dbo"); 
     Table("Services"); 
    } 
} 

任何幫助總是讚賞!


只是一個快速編輯爲周杰倫 - 我不想Session.Load我的元素原因是因爲我不希望我的表現層(MVC 3)關於NHibernate的一無所知 - 因此我使用存儲庫模式並將單個存儲庫注入控制器。因此,例如,我要一個TicketRepository這符合下列合同

public interface IRepository<T> 
{ 
    T GetById(object id); 
    void Create(T entity); 
    void Update(T entity); 
    void Delete(T entity); 
} 

我不希望有注入ServiceRepository也只是爲了獲得到服務參考票務

+1

您可以詳細說明不希望使用'Session.Load'的有效原因嗎? – Jay 2012-08-14 15:45:54

+1

@Jay,不清楚Terric的原因......但是爲了能夠引用您已經保存的密鑰,恕我直言,加載對象有時候可能會是荒謬的。我們對以前的項目有嚴格的SLA,在它支持FK之前,我們必須在Entity Framework上做同樣的工作。 – 2012-08-14 16:20:36

+0

@Jay已經更新我的帖子的原因。此外,凱文提出了一個很好的觀點,我不希望爲這個關聯加載另一個實體的額外開銷。 – 2012-08-14 16:51:29

回答

3

我看你真的不能避免使用NHibernate時使用Session.Load(ID)的方式。正如在註釋中提到的那樣,這不會觸及數據庫,只需使用該id創建一個代理對象即可。

的一些可能的選項:

  1. 注入第二通用信息庫(ServiceRepository)到控制器。我看不出有什麼問題,但出於某種原因,你想避免它。您可以將一個LoadById方法添加到通用接口,並在NH和EF(或其他)的每個實現中以不同的方式實現。在EF impl中,該方法可以像GetById一樣工作,而在NH impl中它會調用Session.Load
  2. 爲AR(聚合根)實現一個非通用存儲庫,在這種情況下,它將成爲Ticket。這可能具有加載服務以及票據的特定方法。
  3. 落實兩個倉庫的頂部另一個抽象並注入該到控制器,而不是兩個庫的選項1,這可能F。ex是一個堅持無知的UnitOfWork,如下所示:Persistance ignorant UoW,或者某種類型的應用服務,協調Tickets或TicketFactory的創建。

在3個選項中,選項1可能是最簡單的,而3可能提供更好的抽象和更可維護性。

+0

謝謝,對'Session.Load'的更好的理解意味着我不再擔心它的使用。我最終使用了實體框架,並刪除了NHibernate(主要是因爲我對EF更加舒適,但想知道NH必須提供什麼)。 – 2012-09-07 10:20:09

+0

我一直在拋棄將我的外鍵轉換爲整數而不是對象的想法,因爲我不想爲每個插入或更新中的每個鏈接對象都敲擊數據庫......直到我遇到此問題並瞭解了Session.Load()。並排比較nhibernate日誌結果進行簡單操作 - 哇!巨大的節省!謝謝! – Brett 2013-03-01 18:37:22

0

你可以使用一個技巧。保持您的代碼清潔。

像這樣是NH的問題,你必須在NH存儲庫中實現它的解決方案,所以我解決它這樣。

之前添加或更新

if (!string.IsNullOrEmpty(ServiceId) && Service == null) 
{ 
    Service = new Service{ Id = ServiceId }; 
} 

正常儲存庫的工作...

我測試和工作。您的體系結構仍然清除ORM決策

+0

假設服務類有多個字段,那麼我們是否需要在這裏分配所有的字段?因爲我面臨同樣的問題.. – jkyadav 2015-08-28 08:15:39