如何使用具有依赖注入的泛型的存储库接口?

时间:2013-01-16 18:54:56

标签: c# dependency-injection unity-container ioc-container

我正在尝试使用以下通用存储库接口进行DI和构造函数注入:

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

问题是为了定义接口的实例,我必须提供类似这样的类类型:

private IRepository<Person> _personRepository;

这个问题是如果我使用DI(我使用Unity for IoC框架),那么我必须在构造函数中定义多个实例以获取我需要使用的所有存储库接口,如下所示: / p>

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. 即使这是正确的,Unity将接口注册到具体类型的重点是什么?我已经完成了,因为通用存储库迫使我申报。
  4. 请帮助我解决这个问题,感谢您的帮助!

5 个答案:

答案 0 :(得分:9)

如D Stanley所述,依赖必须是具体的接口。否则,你要在哪里宣布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>); 

如果您需要特定的类型覆盖(表示Items存储库因任何原因而特殊,因此它具有完全实现的ItemRepository类),只需在通用类型之后注册该特定实现:

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

现在,解析IRespository<Item>将获得您的具体实施。

对于记录,我认为这只能在代码中完成,而不能在配置文件中完成。有人可以随意纠正这个假设。

答案 1 :(得分:2)

  

这样可以吗?

不确定。个人喜欢是否使用像你一样的构造函数注入或属性注入。构造函数注入更清晰,因为您不必为构造函数提供大量参数,但它也更安全。

  

Unity将接口注册到具体类型

的重点是什么

一个原因是,您可以对MyClass进行单元测试,而无需使用实际存储库来访问数据库。您可以“伪造”存储库以返回硬编码值以进行测试。

答案 2 :(得分:2)

您可以考虑使用将多个其他服务捆绑在一起的Aggregate Service,但您还应该仔细查看MyClasstrying to do too much;拥有大量依赖关系可以表明这一点。

答案 3 :(得分:2)

除了一个遗漏点之外,这似乎没问题;您需要UnitOfWork模式来启用事务。 如果未应用UnitOfWork模式,则所有存储库都会尝试在不同的上下文中提交数据库操作。

答案 4 :(得分:0)

我需要使用配置文件来完成此操作。它实际上非常简单,但花了我一段时间来搞清楚。

在这个例子中,我们有一个接口IRepository<T>,它有2个实现:

  1. OneRepository
  2. TwoRepository
  3. 然后我们有一个名为Worker的类,它取决于IRepository<One>IRepository<Two>。我们要求unity为我们创建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 { }
    

    Unity配置

    请注意我们指示团结并告诉它集会的名称。然后我们注册了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