如何在此模式中将EF POCO与通用IRepository分离?

时间:2012-10-29 17:04:28

标签: c# design-patterns repository-pattern dto unit-of-work

我目前有一个Repository / UnitOfWork模式。但是,有一种硬耦合我无法弄清楚如何摆脱它。


这是我的模式概述:

业务逻辑层

  • IRepository
    • 用作类型约束
  • IRepository< TModel,TDTO>
    • 实施IRepository
    • 一般CRUD方法
  • IEmployeeRepository< TModel>
    • 实施IRepository< TModel,EmployeeDTO>
    • 一些员工特定方法
  • IUnitOfWork
    • 存储库的Getter
    • 保存方法
  • IEntityWithId
    • 强制(并公开)DTO和EF POCO以具有名为ID的Int32字段的接口
    • 用作类型约束
  • EmployeeDTO(在已实施的EmployeeRepository中使用AutoMapper映射)
    • 核心项目中使用的DTO实体和(来)测试项目

数据层(使用Ninject注入)

  • 的UnitOfWork
    • 基于实体框架的IUnitOfWork的实现
  • EmployeesRepository
    • IEmployeeRepository的实现< TModel>
  • 员工
    • EF POCO

核心

  • EmployeesController
    • 参数化构造函数EmployeesController(IUnitOfWork unitOfWork)
    • IUnitOfWork注入一个Ninject模块作为UnitOfWork(来自数据层)

这是我的通用IRepository接口中的问题方法。

TDTO Find(Expression<Func<TModel, bool>> filter);

IEnumerable<TDTO> FindAll(Expression<Func<TModel, bool>> filter);

如您所见,其中有TModel,用于构建表达式以过滤结果。我可以做一些事情,比如在DTO上使用表达式,但这需要一个映射到DTO的完整员工列表(也就是说它不会生成SQL过滤器,但它会过滤SELECT * FROM Employee结果列表)。所以这不是一个好的选择。

另一种更可行但非最佳的解决方案是使用动态LINQ。这样,我可以在Find / FindAll方法中传递一个简单的字符串,并摆脱TModel的要求。但是,这意味着重构变得烦人,因为它用魔术字符串填充代码。

2 个答案:

答案 0 :(得分:1)

正如我发布的那样,我想我找出了问题所在。

Find()和FindAll()甚至不应该存在。我应该在IEmployeeRepository中编写更具体的方法,如FindEmployeeByName(字符串名称),然后像这样实现它:

EmployeeDTO FindEmployeeByName(string name)
{
    return Mapper.Map<EmployeeDTO>(dbSet.Where(o=>o.name.Contains(name)).FirstOfDefault());
}

任何人都可以确认这是一种正确的方法吗?或者建议一些更好的东西?

修改

此外,如果我想保留Find(Expression ...)和FindAll(Expression ...)方法,我可以,但它们只是在数据层中,并由实现的方法使用,以避免重复的代码。但它们不应该用在控制器中,因为它们需要知道底层数据结构,而不是我的业务逻辑。也就是说,它们可以在BaseRepository&lt; TModel&gt; (我已经拥有,但没有提到让事情变得更简单)并使EmployeesRepository成为BaseRepository的扩展。这样,每个存储库都已经具有类似通用的方法,即模型识别。

不确定我是否正确解释了这一点。如果不清楚我会告诉我,我会尝试编辑它并使其更好。

答案 1 :(得分:0)

另一种方法是让您的数据层依赖于业务层,并将您的存储库“项目”实体放入业务对象(DTO)中。这样,您的BL位于底部,UI和数据依赖于它,但UI和数据不依赖于彼此。

这是Mark Seemann在他的“依赖注射”一书中提出的方法。