向服务层公开实体框架扩展
本文关键字:实体 框架 扩展 服务 | 更新日期: 2023-09-27 18:17:31
我已经使用IRepository
模式实现了我的数据层。其中一个方法返回一个IQueryable
:
public virtual IQueryable<TEntity> Queryable()
{
return dbSet;
}
我也有一个服务层调用这个方法来提供过滤,例如:
public User GetByName(string name)
{
return _repository.Queryable()
.Where(a => a.Name == name)
.ToList();
}
到目前为止,实体框架只在数据层被引用,服务层对此一无所知。
现在,我想做另外两件事:
- 使用
Include
方法 - 使用
ToListAsync()
方法
现在我的service方法是这样的
public async Task<User> GetByName(string name)
{
return await _repository.Queryable()
.Where(a => a.Name == name)
.Include(x => x.Pets)
.ToListAsync();
}
现在的问题是,Include()
和ToListAsync()
都在System.Data.Entity
命名空间,这是在EntityFramework.dll
。
我不想从我的服务层中引用EF,它不应该关心或知道这个,但不知道如何在保持架构干净的情况下解决这个问题。我能想到的唯一解决方案是:
- 添加实体框架到服务层
- 添加一个新的类到数据层(
UserData
)包装IRepository<User>' and handles the two additional methods required. The service will then take use an instance of this rather than
IRepository '。
有什么建议我如何解决这个问题,同时仍然坚持最佳实践?
我理解您希望基于最佳实践在存储库层中抽象EF。但是你的用例(你这里的主要问题)是一个矛盾——你想把EF提供的所有东西都公开给你的服务层。
听起来您需要定义一个严格的行来定义这个存储库的职责是什么。如果它是返回一个IQueryable
,那么包装EF有什么好处呢?您是否计划在生产环境中实际使用其他存储库实现?如果是这样,当您公开IQueryable
时,将很难确保两个回购类型都是正确的。这就是你现在看到的痛点。
在我看来,存储库应该定义如何获取数据。它应该公开像GetAllUsers
这样返回实际模型的简单调用。当您让业务/服务层定义自己获取数据的方式时,它会让存储库感觉是多余的。
Include和ToListAsync驻留在EF中,因此它们应该保存在EF服务中。
不需要提供对System的引用而访问它们的唯一方法。实体是创建您自己的代理方法。在一天结束的时候,你应该在高层次上编写你的应用程序所需的代码,而不是确保它可以访问EF所能访问的所有内容。
当我处理EF时,我创建了一个服务/上下文层,一个存储库层,然后是一个抽象EF技术的客户端层。这是由其他开发者/用户使用的,所以他们不会过多地暴露在EF方面。我只是锻炼了应用程序所需要的东西,并实现了这样做的方法,仅此而已。引入系统的功能没有什么意义。实体,它们应该在客户端级别抽象掉。
我讨厌的一件事是,如果我想让我的服务/上下文层与应用程序的其他部分保持距离,就必须复制模型。为了解决这个问题,我有一个模型工厂,它使用DI来查找EF模型并通过DI容器交付它们。它只是意味着我必须为我创建的每个模型添加一个接口。不要紧。