我是DI的新手,我正在开发一个MVC项目,其中一个控制器被注入一个UnitOfWork,而这个UnitOfWork包含我域中每个实体类型的存储库。使用MSDN作为指南,我最初有类似
的内容public IRepository<Employee> Employees {
get {
if (_employees == null) {
_employees = new SqlRepository<Employee>(_context);
}
return _employees;
}
}
但是,我认为注入存储库会很好,例如:
public SqlUnitOfWork(IRepository<Employee> employees)
{
this.Employees = employees;
}
但是如果创建SqlRepository非常昂贵。并非每个控制器操作都使用每个存储在我更改为DI之前,只有在访问它们时才会创建每个存储库。但是,现在所有存储库都是使用UnitOfWork创建的。当我已经在SqlUnitOfWork中时,我试图确定是否值得注入SqlRepositories?或者,我应该遵循MSDN示例吗?
答案 0 :(得分:1)
我不是ASP.NET MVC用户,但dependency injection方法背后的想法不会改变。所以,用盐粒。
根据您的描述,您正在使用具有工作单元的多个存储库,并且您无法决定是注入它们还是在其中创建。最好的课程是:既不。
当您处理未知数量的相同类型的依赖项时,更明智的是注入工厂实例。然后,您的UnitOfWork
实施可以从所述工厂请求服务。
在这种情况下,工厂会检查是否已初始化此类服务。如果已初始化此类服务,则可以将其返回。如果没有,您初始化该服务,将其缓存(最有可能在工厂内的某些类似阵列的结构中)并返回该实例。
其他一些说明
存储库和工作单元都不应暴露给控制器。它们是负责处理存储的结构。您最终会将模型图层的内部详细信息暴露给表示层。基本上,你的抽象漏掉了。
我会仔细阅读该教程。看来该文章的作者没有完全掌握DI的概念。如果你看一下这段代码:
public class SqlUnitOfWork : IUnitOfWork {
public SqlUnitOfWork() {
var connectionString =
ConfigurationManager
.ConnectionStrings[ConnectionStringName]
.ConnectionString;
_context = new ObjectContext(connectionString);
}
/* --- SNIP --- */
readonly ObjectContext _context;
const string ConnectionStringName = "EmployeeDataModelContainer";
}
您可以看到数据库连接是在构造函数中初始化的,基于常量,已在SqlUnitOfWork
类的定义中进行了硬连线。 这是一种非常糟糕的做法。
如果您想了解更多关于OOP实践的依赖注入的信息,我建议您watch this lecture和相同系列的讲座。
答案 1 :(得分:0)
你担心注入一个昂贵的创造对象是正确的。
依赖注入依赖于能够廉价地创建和注入对象(其中一些可能永远不会被使用)。这就是为什么在构造函数中或在构建对象图时执行“实际工作”是一个坏主意。
这里的问题是IRepository
创建起来很昂贵。如果它在构造函数中执行“实际工作”,您可以稍后将其移动到需要之前吗?这有点像懒惰的评价。这解决了问题的根本原因。
有时,这是不可能的。有解决方法:
答案 2 :(得分:0)
为昂贵的依赖项注入工厂意味着该依赖项的使用者知道依赖项接口有一个昂贵的实现。如果消费者相应地改变了它的实现,这是一个漏洞的抽象。
看看this blog post。它展示了如何生成一个使用Unity即时实现存储库接口的惰性代理。
According to this thread Castle Windsor也可以这样做。