我看过很多关于 UnitOfWork 和 Repository 的帖子(和辩论!)。我喜欢的存储库模式之一是类型化的通用存储库模式,但我担心这会导致一些干净的代码和可测试性问题。采用以下存储库接口和泛型类:
public interface IDataEntityRepository<T> : IDisposable where T : IDataEntity
{
// CRUD
int Create(T createObject);
// etc.
}
public class DataEntityRepository<T> : IDataEntityRepository<T> where T : class, IDataEntity
{
private IDbContext Context { get; set; }
public DataEntityRepository (IDbContext context)
{
Context = context;
}
private IDbSet<T> DbSet { get { return Context.Set<T>(); } }
public int Create(T CreateObject)
{
DbSet.Add(createObject);
}
// etc.
}
// where
public interface IDbContext
{
IDbSet<T> Set<T>() where T : class;
DbEntityEntry<T> Entry<T>(T readObject) where T : class;
int SaveChanges();
void Dispose();
}
所以基本上我在每个模式中使用 Context 属性来访问底层上下文。我现在的问题是:当我创建我的工作单元时,它实际上是我需要存储库知道的上下文的包装器。因此,如果我有一个声明以下内容的工作单元:
public UserUnitOfWork(
IDataEntityRepository<User> userRepository,
IDataEntityRepository<Role> roleRepository)
{
_userRepository = userRepository;
_roleRepository = roleRepository;
}
private readonly IDataEntityRepository<User> _userRepository;
public IDataEntityRepository<User> UserRepository
{
get { return _userRepository; }
}
private readonly IDataEntityRepository<Role> _roleRepository;
public IDataEntityRepository<Role> RoleRepository
{
get { return _roleRepository; }
}
我有一个问题,即我传入的两个存储库都需要使用它们被传递到的工作单元进行实例化。显然,我可以在构造函数中实例化存储库并传入“this”,但这会将我的工作单元与存储库的特定具体实例紧密耦合,并使单元测试变得更加困难。我很想知道是否还有其他人沿着这条路走并撞到了同一堵墙。这两种模式对我来说都是新的,所以我很可能会做一些根本错误的事情。任何想法将不胜感激!
更新(回复@MikeSW)
嗨,迈克,非常感谢您的意见。我正在使用 EF Code First,但我想抽象某些元素,以便在需要时切换到不同的数据源或 ORM,因为我(正在尝试!)将自己推向 TDD 路线并使用 Mocking 和 IOC。我想我已经意识到某些元素不能在纯粹意义上进行单元测试但可以进行集成测试的艰难方式!我想就存储库与业务对象或视图模型等一起工作提出您的观点。也许我误解了,但如果我有我认为的核心业务对象 (POCO),然后我想使用 ORM,例如 EF 代码首先环绕这些实体以创建数据库,然后与之交互(并且,有可能,我可以在 ViewModel 中重用这些实体),我希望存储库能够在一组 CRUD 操作的上下文中直接处理这些实体。实体对持久层一无所知,任何 ViewModel 也不知道。我的工作单元只是实例化并保存允许执行事务提交的所需存储库(跨多个存储库但相同的上下文/会话)。我在我的解决方案中所做的是从 UnitOfWork 构造函数中删除 IDataEntityRepository ...等的注入,因为这是一个具体的类,它必须知道它应该创建的一种且只有一种类型的 IDataEntityRepository(在本例中为 DataEntityRepository , 这确实应该更好地命名为 EFDataEntityRepository)。我无法对其本身进行单元测试,因为整个单元逻辑将是建立具有某个数据库的上下文(本身)的存储库。它只需要一个集成测试。希望这是有道理的?!