2010-09-13 79 views
2

這只是我一直在想的問題,並想知道它是否存在,或者即使它有益。NHibernate與控制反轉

我正在做使用Unity的控制和依賴注入的反轉。我也用流利的nHibernate做ORM。我想知道是否有辦法配置nHibernate將接口作爲其類型參數併爲我做IoC,或者將它們一起使用的最佳方式是。例如,如果我有一個使用存儲庫模式的客戶對象,我可能會有2個接口(ICustomer,ICustomerRepository)以及2個具體實現(Customer,CustomerRepository)。在具體的CustomerRepository中,我必須將其直接綁定到Customer對象以便使用nHIbernate。

public class CustomerRepository : ICustomerRepository 
{ 
    public ICustomer Retrieve(int id) 
    { 
     return _session.Get<Customer>(id); 
    } 
} 

不是傳遞「客戶」作爲類型參數的會議,我認爲這將是冷靜傳「ICustomer」和莫名其妙地NHibernate的配置做的IoC。這甚至是可能的,還是有益的?

+2

它爲什麼「很酷」? – Paco 2010-09-13 14:35:56

+0

您不應該使用域對象的接口。 – Chris 2012-06-27 07:10:55

回答

1

當我們開始設計我們的應用程序,我有相同的想法。但是,很快我們遇到了僅使用基於接口的類型的一些問題,所以我們通過使用具體類型和寬鬆的存儲庫(即Customer和ICustomerRepository)來妥協。

我想回想一下我們遇到了什麼問題,但現在我已經空白了。

+0

這就是我最終做的。我意識到連接我的對象以及我的存儲庫沒有太大的好處。 – 2011-01-04 16:24:29

1

我看不出有什麼很大的靈活性,從這樣做,但實現你的要求,你可以嘗試什麼:

public abstract class AbstractCustomerRepository<T> : ICustomerRepository where T : class, ICustomer 
{ 
    public ICustomer Retrieve(int id) 
    { 
     return _session.Get<T>(id); 
    } 
} 

public class CustomerRepository : AbstractCustomerRepository<Customer> 
{ 

} 
+0

+1 ...除了您可能想要返回'ICustomer'而不是'T'。當應用程序具有多種類型的Customer和CustomerRepository時,這很有用。我上週實現了這個功能,因爲應用程序可以在兩種不同的NH配置下運行。在任何給定的實例中,只有一個會被使用,但是兩者都是在程序集中定義的,並且抽象存儲庫消除了代碼重複。 – Jay 2010-09-13 15:49:31

+0

滾動,其中T:class,ICustomer – wal 2010-09-14 00:48:49

+0

這是不一樣的,事實上甚至不會編譯。如果'ICustomerRepository'聲明'Retrieve'方法返回'ICustomer',它的實現者必須聲明'ICustomer'作爲返回值。 – Jay 2010-09-15 15:24:20

1

將NHibernate中的ICustomer投擲出來並沒有真正的優勢。 NHibernate本身應該只是一個帶有幾個鉤子的黑盒子,你可以在其中附加你的模擬。正如你可以在NHibernate中模擬實現一樣;它並不關心裏面使用什麼對象。

當嘲笑這種方法時,你可以用NHibernate的ISessionIQuery以及你自己的代碼中的ICustomerRepository來完成所有這些。不需要添加額外的抽象。


哦,順便說一句,爲什麼有NHibernate作爲額外的IoC容器,當你的存儲庫已經是?

0

如果你打算有一個ICustomer接口,這會建議你想用Customer替代別的東西嗎?情況會是這樣嗎?如果是的話,用什麼?

您的客戶類應該是您的域的一部分,以及其他實體,如產品,訂單等等。您的域應該構成整個應用程序的核心部分。我認爲你的努力應該轉向讓你的域實體與你的NHibernate數據訪問代碼脫鉤,這似乎是你使用Repository接口實現的。

如果你想創建一個特定的客戶實施基礎客戶,然後用繼承,這NHibernate的支持非常好:

public abstract class Customer { } 

public class EnterpriseCustomer : Customer { } 
public class SmbCustomer : Customer { } 
public class IndividualCustomer : Customer { } 

NHibernate的是足夠強大,當你調用return _session.Get<Customer>(id);實例正確的類型,而不必明確地施展它自己。

也許這就是你所追求的。看一看NHibernate的文檔上繼承:http://nhibernate.info/doc/nh/en/index.html#inheritance

+0

我完全同意你的意見,但我認爲這隻適用於POCO類型的設置。如果您在沒有POCO的情況下使用實體,那麼您的業務對象將專門綁定到您的ORM,這就需要將它們與您的存儲庫進行接口連接。因爲非POCO實體對象會被nHibernate對象不具有的額外代碼所淹沒。 – 2010-09-15 14:26:29

1

一個辦法整合您的IOC容器(團結)與NHibernate,是用團結來解決,你會傳遞給NHibernate的類型。

這實現了我認爲你的目標,即在一個地方只有一個接口和實現之間的映射。

public CustomerRepository : ICustomerRepository 
{ 
    Type customerType; 

    // ISession[Factory] injection omitted for brevity 

    public CustomerRepository(IUnityContainer container) 
    { 
     registration = container.Registrations.FirstOrDefault(
      x => x.RegisteredType.Equals(ICustomer)); 

     if(registration == null) 
     { 
      throw new ApplicationException(
       "No ICustomer implementation was registered."); 
     } 

     customerType = registration.MappedToType; 
    } 

    public ICustomer Retrieve(int id) 
    { 
     return _session.Get(customerType, id); 
    } 
} 

很顯然,你不能使用NHibernate的通用重載,但我認爲他們都有着非一般等價物。

您必須參考具體實施的另一個地方在您的FNH ClassMap<T> s。

+0

這實際上是一個非常酷的主意!我甚至沒有想過這樣做,謝謝傑伊! – 2010-09-15 14:27:53

0

使用國際奧委會將找到ICustomerRepository

在你的客戶端代碼的具體實施

//的例子。

ICustomerRepository dao = ServiceFactory.GetServiceInstance<ICustomerRepository>(); 

// a的服務工廠

public static class ServiceFactory 
{ 
     private WindsorContainer m_container; 

     public static T GetServiceInstance<T>() 
     { 
       // use your IOC to resolve your <T> 
       return m_container.Resolve<T>(); 
     } 
} 

在上面的示例框架,我使用溫莎城堡作爲我的國際奧委會。請調整您的實施以使用Unity Block。

我希望你能對我有所瞭解。

+0

嘿Syd,我實際上使用了一個類似於此的模式來獲取我的存儲庫的具體實現。我只是想在nHibernate中使用具體的存儲庫來將接口映射到具體的實現,所以我可以將nHibernate會話傳遞給一個接口,並讓它自動爲我解析依賴關係。 – 2010-09-15 14:31:38