向服务层公开实体框架扩展

本文关键字:实体 框架 扩展 服务 | 更新日期: 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();
}

到目前为止,实体框架只在数据层被引用,服务层对此一无所知。

现在,我想做另外两件事:

  1. 使用Include方法
  2. 使用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,它不应该关心或知道这个,但不知道如何在保持架构干净的情况下解决这个问题。我能想到的唯一解决方案是:

  1. 添加实体框架到服务层
  2. 添加一个新的类到数据层(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容器交付它们。它只是意味着我必须为我创建的每个模型添加一个接口。不要紧。