我在这里使用EF6的通用统一工作: https://genericunitofworkandrepositories.codeplex.com/
我有一个使用两个数据库的应用程序。我已经创建了额外的UnitOfWork接口和实现原始工作单元接口的类:
namespace Repository.Pattern.UnitOfWork
{
public interface ILotteryBackOfficeUnitOfWorkAsync : IUnitOfWorkAsync
{
}
}
第二个数据库初始化的第二工作单元类型:
namespace Repository.Pattern.Ef6
{
public class LotteryBackOfficeUnitOfWork : UnitOfWork, ILotteryBackOfficeUnitOfWorkAsync
{
public LotteryBackOfficeUnitOfWork(IDataContextAsync dataContext)
: base(dataContext)
{ }
}
}
在统一中,我为不同的数据上下文注册了两个工作单元:
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your types here
// container.RegisterType<IProductRepository, ProductRepository>();
var purusLotteryConnectionString = WebConfigurationManager.ConnectionStrings["PurusLotteryContext"].ConnectionString;
var purusLotteryBackOfficeConnectionString = WebConfigurationManager.ConnectionStrings["PurusLotteryBackOfficeContext"].ConnectionString;
container.RegisterType<IDataContextAsync, PurusLotteryContext>(new InjectionConstructor(purusLotteryConnectionString));
container.RegisterType<IUnitOfWorkAsync, UnitOfWork>(new HierarchicalLifetimeManager());
container.RegisterType<IDataContextAsync, PurusLotteryBackOfficeContext>("LotteryBackOfficeContext", new InjectionConstructor(purusLotteryBackOfficeConnectionString));
container.RegisterType<ILotteryBackOfficeUnitOfWorkAsync, LotteryBackOfficeUnitOfWork>(new HierarchicalLifetimeManager(),
new InjectionConstructor(container.Resolve<IDataContextAsync>("LotteryBackOfficeContext")));
container.RegisterType<IHomeService, HomeService>();
}
它有效,但这是正确的程序吗?
答案 0 :(得分:3)
我看到的一个错误是您在注册阶段解决了。这不仅是危险的(在不同的DI库的文档中也是explained),在你的情况下它导致PurusLotteryBackOfficeContext
被用作常量,因此被注入为 Singleton 进入LotteryBackOfficeUnitOfWork
。换句话说,虽然这似乎在开发过程中起作用,但这不起作用,因为DbContext
can't be used as singleton。
相反,您应该尽可能多地使用Unity的自动布线功能,否则DI库在构建对象图by hand方面没有优势(而且只是缺点)。
除此之外,您违反了设计中的Liskov Substitution Principle(LSP),这会导致DI配置出现问题。您违反了LSP,因为您有两个相同抽象的不兼容实现。 PurusLotteryContext
和PurusLotteryBackOfficeContext
都实现IDataContextAsync
,但它们不兼容,因为它们不能互换,因为它们都在完全不同的数据库模式上工作。虽然它们似乎共享相同的界面,但它们不共享相同的合同。只需看看当您将PurusLotteryContext
注入需要与后台一起工作的某个类时会发生什么。应用程序将中断,这意味着您违反了LSP。
解决方案是给他们自己独立的抽象。起初这可能看起来很奇怪,因为它们都有相同的方法。但请记住,界面不仅仅是一组方法签名;接口描述了契约和行为,并且由于两个实现都在完全不同的数据库模式上工作,因此它们具有完全不同的契约。当您将其分开时,您的代码将如下所示:
public class PurusLotteryContext : IPurusLotteryDataContextAsync {
public PurusLotteryContext(string conString) : base(conString) { }
}
public class LotteryUnitOfWork : ILotteryUnitOfWorkAsync {
public LotteryUnitOfWork(IPurusLotteryDataContextAsync dc) { }
}
public class PurusLotteryBackOfficeContext : IPurusLotteryBackOfficeDataContextAsync {
public PurusLotteryBackOfficeContext(string conString) : base(conString) { }
}
public class LotteryBackOfficeUnitOfWork : ILotteryBackOfficeUnitOfWorkAsync {
public LotteryBackOfficeUnitOfWork(IPurusLotteryBackOfficeDataContextAsync dc) { }
}
这允许您进行以下注册:
container.Register<IPurusLotteryDataContextAsync>(new HierarchicalLifetimeManager(),
new InjectionFactory(c => new PurusLotteryContext(purusLotteryConnectionString)));
container.Register<IPurusLotteryBackOfficeDataContextAsync>(
new HierarchicalLifetimeManager(),
new InjectionFactory(c => new PurusLotteryBackOfficeContext(
purusLotteryBackOfficeConnectionString)));
container.RegisterType<ILotteryUnitOfWorkAsync, LotteryUnitOfWork>(
new HierarchicalLifetimeManager());
container.RegisterType<ILotteryBackOfficeUnitOfWorkAsync, LotteryBackOfficeUnitOfWork>(
new HierarchicalLifetimeManager());
请注意有关此注册的一些事项:
答案 1 :(得分:1)
我知道我的答案来得很晚,但我想指出一个不同的方向,而不是@Steve建议。
命名注册怎么样?使用名称注册具有不同实现的相同接口。理解你有合同和不同的实施,没有任何错误。
如果您想在注册两个实现时保持相同的界面,可以使用其他名称进行操作,请查看下面的答案
https://stackoverflow.com/a/18665983
现在,LSP的意图是派生类型必须完全可替代其基类型,并且在您的情况下不会创建具有相同功能和不同签名的新合同。我不同意@Steve的建议。 Bellow我附上一个很好的LSP例子
https://stackoverflow.com/a/584732/819153
另一个兴趣点是UnitOfWork。
当您使用EntityFramework并实例化DbContext时 - 你正在创建一个新的UnitOfWork.With EntityFramework你可以通过使用SaveChanges()“刷新并重置”UnitofWork,你不需要SaveChanges只返回新的ID - EF已经在事务范围内完成了!
这是一篇很好的文章,你可以阅读它。
http://rob.conery.io/2014/03/04/repositories-and-unitofwork-are-not-a-good-idea/
我建议直接注入DataContext而不是IUnitOfWork
希望这个帮助