我正在尝试使用以下通用存储库接口进行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;
}
问题:
请帮助我解决这个问题,感谢您的帮助!
答案 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,但您还应该仔细查看MyClass
是trying to do too much;拥有大量依赖关系可以表明这一点。
答案 3 :(得分:2)
除了一个遗漏点之外,这似乎没问题;您需要UnitOfWork模式来启用事务。 如果未应用UnitOfWork模式,则所有存储库都会尝试在不同的上下文中提交数据库操作。
答案 4 :(得分:0)
我需要使用配置文件来完成此操作。它实际上非常简单,但花了我一段时间来搞清楚。
在这个例子中,我们有一个接口IRepository<T>
,它有2个实现:
OneRepository
TwoRepository
然后我们有一个名为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>
<强>应用强>
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