2013-01-16 58 views
12

我試圖使用DI和構造器注入下面的通用倉庫接口:如何使用依賴注入使用泛型的存儲庫接口?

public interface IRepository<TEntity> : IDisposable where TEntity : class 

的問題是爲了定義的接口的實例,我必須提供一流的類型是這樣的:

private IRepository<Person> _personRepository; 

這個問題是如果我使用DI(並且我正在使用Unity for IoC框架),那麼我必須在我的構造函數中定義多個實例來獲取我需要使用的所有存儲庫接口,如下所示:

public MyClass(IRepository<Person> personRepository, 
       IRepository<Orders> ordersRepository, 
       IRepository<Items> itemsRepository, 
       IRepository<Locations> locationsRepository) 
{ 
    _personRepository = personRepository; 
    _OrdersRepository = ordersRepository; 
    _itemsRepository = itemsRepository; 
    _locationsRepository = locationsRepository; 
} 

問題:

  1. 這樣行嗎?
  2. 如果不是我失去了這個概念的地方?
  3. 即使這是正確的,註冊Interface到具體類型的Unity有什麼意義?我已經做到了,因爲通用的存儲庫迫使我聲明。

請幫我解決這個問題,我感謝您的幫助!

回答

2

可以嗎?

當然。對於是否使用構造函數注入或個人注入有個人偏好。構造函數注入更清潔,因爲您不必爲構造函數提供很多參數,但它也更安全。

什麼是統一點接口註冊到具體類型

一個原因是讓你可以單元測試MyClass,而不必使用命中數據庫實際存儲庫。您可以「僞裝」存儲庫以返回硬編碼的值進行測試。

+0

我希望我可以做的是有'IRepository repository'作爲方法的參數,但我知道這是行不通的。你能解釋爲什麼它不會嗎?感覺錯了,所有這些都通過了,但也許它是正確的,我是過度思考。 – atconway

+1

由於每個存儲庫都是不同的類型,MyClass(顯然)需要4個不同的存儲庫。你必須分別提供具體的類。以某種方式注入多個依賴關係並不錯(或不常見)。 –

+0

但是什麼時候需要額外的方法呢? – krypru

2

您可以考慮使用將多個其他服務捆綁在一起的Aggregate Service,但您還應仔細查看MyClass是否爲trying to do too much;擁有非常大量的依賴關係可以說明這一點。

+1

本特例中的綜合服務稱爲[工作單元](http://martinfowler.com/eaaCatalog/unitOfWork.html)。 – Steven

2

這似乎確定除了一個缺失點;您需要UnitOfWork模式來啓用事務。 如果沒有應用UnitOfWork模式,所有存儲庫都會嘗試在不同的上下文中提交數據庫操作。

+0

他的問題中沒有任何一點指向要求UoW的他。正如其他人指出的,也許他的班級做得太多了,但他從未說過要試圖一次對所有存儲庫進行修改。另外,在技術上,不同的存儲庫不一定使用不同的上下文。 – Tipx

9

正如D斯坦利所指出的,依賴必須是一個具體的接口。否則,你要在哪裏聲明T?你的依賴類可能是通用的,但你仍然必須在某個時候說「T是一個人」。

也就是說,Unity很好地處理了註冊泛型類型。

假設你實施IRepository<T>Repository<T>通用類包裝DbSet<T>(或其他)。

下注冊,然後做出決議將工作(包括注入任何構造函數):

container.RegisterType(typeof(IRepository<>), typeof(Repository<>)); 

// no specific registration needed for the specific type resolves 
container.Resolve(<IRepository<Person>); 
container.Resolve(<IRepository<Order>); 

如果你需要一個類型(具體覆蓋說,項目庫是專門爲所以它不管是什麼原因一個完全實現ItemRepository類),只需註冊一個具體實施通用一個後:

container.RegisterType<IRepository<Item>, ItemRepository>(); 

解決IRespository<Item>現在會得到你的具體實施。

爲了記錄,我認爲這隻能在代碼中完成,而不能在配置文件中完成。有人可以自由地糾正這個假設。

+1

您可以在Unity配置文件中註冊通用類。我已經做了。 ''就是一個例子。愛我一些團結。 –

0

我需要使用配置文件來做到這一點。這其實很簡單,但花了我一段時間才弄明白。

在這個例子中,我們有一個接口IRepository<T>,它有2個實現:

  1. OneRepository
  2. TwoRepository

然後我們有一個名爲Worker類取決於IRepository<One>IRepository<Two>。我們要求統一爲我們創建一個Worker的實例,並從配置文件中找出依賴關係。

接口和實現

所有這些都是在這個例子中,命名空間ConsoleApplication1

public class Worker 
{ 
    private readonly IRepository<One> one; 
    private readonly IRepository<Two> two; 

    public Worker(IRepository<One> one, IRepository<Two> two) 
    { 
     this.one = one; 
     this.two = two; 
    } 

    public string DoOne() 
    { 
     return this.one.Add(new One()); 
    } 

    public string DoTwo() 
    { 
     return this.two.Add(new Two()); 
    } 
} 

public interface IRepository<T> 
{ 
    string Add(T t); 
} 

public class OneRepository : IRepository<One> 
{ 
    public string Add(One t) 
    { 
     return "One"; 
    } 
} 

public class TwoRepository : IRepository<Two> 
{ 
    public string Add(Two t) 
    { 
     return "Two"; 
    } 
} 

public class One { } 
public class Two { } 

統一配置

請注意我們指示統一,並告訴它的程序集的名稱。然後我們註冊了2個實現。

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 
    <configSections> 
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" /> 
    </configSections> 
    <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> 
    <assembly name="ConsoleApplication1" /> 
    <container> 
     <register type="ConsoleApplication1.IRepository[[ConsoleApplication1.One]]" mapTo="ConsoleApplication1.OneRepository" /> 
     <register type="ConsoleApplication1.IRepository[[ConsoleApplication1.Two]]" mapTo="ConsoleApplication1.TwoRepository" /> 
    </container> 
    </unity> 
</configuration> 

應用

這是Composition Root

public class Program 
{ 
    static void Main() 
    { 
     UnityContainer container = new UnityContainer(); 
     var res = container.LoadConfiguration(); 
     Worker worker = res.Resolve<Worker>(); 
     Console.WriteLine(worker.DoOne()); 
     Console.WriteLine(worker.DoTwo()); 
     Console.Read(); 
    } 
} 

預期的輸出是:

One 
Two