gpt4 book ai didi

repository-pattern - 工作单元和存储库相互依赖

转载 作者:行者123 更新时间:2023-12-04 23:25:01 25 4
gpt4 key购买 nike

我看过很多关于 UnitOfWork 和 Repository 的帖子(和辩论!)。我喜欢的存储库模式之一是类型化的通用存储库模式,但我担心这会导致一些干净的代码和可测试性问题。采用以下存储库接口(interface)和泛型类:

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。我想我已经意识到某些元素不能在纯粹意义上进行单元测试但可以进行集成测试的艰难方式!我想就存储库与业务对象或 View 模型等一起工作提出您的观点。也许我误解了,但如果我有我认为的核心业务对象 (POCO),然后我想使用 ORM,例如 EF 代码首先包装这些实体以创建数据库,然后与数据库交互(并且,我可能会在 ViewModel 中重用这些实体),我希望存储库直接在上下文中处理这些实体一些 CRUD 操作。实体对持久层一无所知,任何 ViewModel 也不知道。我的工作单元只是实例化并保存允许执行事务提交的所需存储库(跨多个存储库但相同的上下文/ session )。我在我的解决方案中所做的是从 UnitOfWork 构造函数中删除 IDataEntityRepository ...等的注入(inject),因为这是一个具体的类,它必须知道它应该创建的一种且只有一种类型的 IDataEntityRepository(在本例中为 DataEntityRepository , 这确实应该更好地命名为 EFDataEntityRepository)。我无法对其本身进行单元测试,因为整个单元逻辑将是建立具有某个数据库的上下文(本身)的存储库。它只需要一个集成测试。希望这是有道理的?!

最佳答案

为避免依赖工作单元中的每个存储库,您可以使用基于此契约(Contract)的提供程序:

public interface IRepositoryProvider
{
DbContext DbContext { get; set; }
IRepository<T> GetRepositoryForEntityType<T>() where T : class;
T GetRepository<T>(Func<DbContext, object> factory = null) where T : class;
void SetRepository<T>(T repository);
}

然后你可以将它注入(inject)到你的 UoW 中,如下所示:
public class UserUnitOfWork: IUserUnitOfWork
{
public UserUnitOfWork(IRepositoryProvider repositoryProvider)
{
RepositoryProvider = repositoryProvider;
}

protected IDataEntityRepository<T> GetRepo<T>() where T : class
{
return RepositoryProvider.GetRepositoryForEntityType<T>();
}

public IDataEntityRepository<User> Users { get { return GetRepo<User>(); } }
public IDataEntityRepository<Role> Roles { get { return GetRepo<Role>(); } }
...

关于repository-pattern - 工作单元和存储库相互依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14205174/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com