我正在实施工作单位。这是我界面的一部分:
public interface IUnitOfWork
{
void Add(object entity);
void Update(object entity);
void Delete(object entity);
void Commit();
}
从我在网上或书中找到的例子来看,工作单元被迫使用“对象”类型,因为我们可以向uow添加任何“类型”的实体。
在提交Commit()之前没什么大不了的。当我提交时,给定一个实体类型,我需要根据实体类型查找存储库,然后调用相应的操作。
例如,我有一个名为Expert
的实体类型public class Expert
{
public object ID { get; set; }
public string Name { get; set; }
}
Expert有一个名为ExpertRepository的存储库。我的应用程序中的所有存储库都实现了IRepository:
public interface IRepository<T>
{
void Create(T item);
void Update(T item);
void Delete(T item);
}
public class ExpertRepository : IRepository<Expert>
{
public void Create(Expert item)
{
//TSQL to insert
}
public void Update(Expert item)
{
//TSQL to update
}
public void Delete(Expert item)
{
//TSQL to delete
}
}
我想澄清一下,我的存储库不负责从我的uow添加,更新或删除实体,相反,我将消费代码(可能在服务层中)新的uow,然后直接添加到它...当我的应用程序准备就绪时,它将调用Commit()。
这有两件事。它允许我的消费代码决定它希望实体如何持久化。消费代码可以直接在Repository上调用.Create()来持久保存实体,或者消费代码可以启动uow,在uow上调用.Add(),然后调用.Commit()时, uow将遍历所有实体,并通过操作类型(添加,更新删除),新建相应的存储库,并执行TSQL代码。
现在,我遇到的问题是当我在我的uow中循环添加,更新和删除集合时。这是一段代码:
public void Commit()
{
using (TransactionScope tx = new TransactionScope())
{
try
{
foreach (object item in addedItems)
{
if (item.GetType() == typeof(Expert))
{
IRepository<Expert> repository = new ExpertRepository();
repository.Create((Expert)item);
}
}
}
}
}
我必须通过item变量解析对象集合中的内容的实体类型。然后我需要新建该实体的Repository(也为IRepository接口提供正确的类型),然后调用.Create()。
这一切都很好,但是我不希望对每个可能的实体,实体的接口以及坐在我的uow中的实体的存储库进行这些条件检查。那非常糟糕。
我知道IoC容器可以在这里提供帮助(例如Unity),但是有没有可以在运行时解析泛型类型的IoC容器?我问,b / c IRepository需要正确输入,才能成为保存给定实体存储库实例的var。
我在这里做了一些设计决定,例如使用存储库进行强类型处理,而不是UOW。例如,我不希望.Create()方法位于一个采用类型对象的存储库,特别是。因为我的存储库与我的实体(Expert,ExpertRepository)有一对一的关系。
我还决定,由于大多数存储库调用都是相同的,我不希望每个存储库都有一个接口(也就是说,ExpertRepository实现了IExpertRepository)。这没有意义,我认为在这里使用泛型就是答案。
但这一切都归结为我的问题。我如何得到正确实现它所需要的东西。
任何有正确方向的建议或指示都将受到赞赏。
谢谢!
答案 0 :(得分:1)
IoC是要走的路。其中一些支持开放式泛型。我们来看StructureMap as an example。您需要具有与此类似的注册码:
// default implementation
x.For(typeof(IRepository<>)).Use(typeof(DefaultRepository<>));
// specific implementations
x.For<IRepository<Expert>>().Use<ExpertRepository>();
然后,您的Commit
方法可以向容器询问给定类型的实现:
_container.ForGenericType(typeof(IRepository<>))
.WithParameters(item.GetType())
.GetInstanceAs<IRepository>();
(您需要使用非通用的IRepository
接口来满足Commit
方法的需求,但我相信在实施方式不同时也没问题。