将实体框架扩展暴露给服务层

时间:2016-11-10 15:52:55

标签: c# entity-framework architecture n-tier-architecture

我使用IRepository模式实现了我的数据层。其中一种方法返回IQueryable

public virtual IQueryable<TEntity> Queryable()
{
        return dbSet;
}

我还有一个Service层,它调用这个提供过滤的方法,例如:

public User GetByName(string name)
{
    return _repository.Queryable()
        .Where(a => a.Name == name)
        .ToList();
}

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

现在,我想再做两件事:

  1. 使用Include方法
  2. 使用ToListAsync()方法
  3. 所以现在我的服务方法如下:

    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`的数据层(IRepository<User>' and handles the two additional methods required. The service will then take use an instance of this rather than)。
    3. 关于如何在坚持最佳做法的同时解决这个问题的任何建议?

2 个答案:

答案 0 :(得分:1)

据我所知,您希望根据最佳实践抽象出存储库层中的EF。但是您的使用案例(这里的主要问题)与此相矛盾 - 您希望公开EF为您的服务层提供的所有内容。

听起来您需要定义一个严格的关于此存储库的责任的行。如果它要返回IQueryable,那么包装EF的好处是什么?您是否计划在生产中实际使用其他存储库实施?如果是这样,当您公开IQueryable时,确保两种回购类型都是正确的将非常困难。这是你现在看到的痛点。

在我看来,存储库应该定义如何获取数据。它应该暴露像GetAllUsers之类的简单调用来返回实际模型。当您让业务/服务层定义自己获取数据的方式时,它会使存储库感到多余。

答案 1 :(得分:0)

在EF中包含和ToListAsync,因此它们应保存在EF服务中。

访问这些而不必提供对System.Entity的引用的唯一方法是创建自己的代理方法。在一天结束时,您应该在高级别编写应用程序所需的代码,而不是确保它可以访问EF可以访问的所有内容。

当我处理EF时,我创建了一个服务/上下文层,一个存储库层,然后是一个客户层,它抽象出EF技术细节。然后,这是其他开发者/用户的用户,因此他们不会向EF方面暴露太多。我只是锻炼应用程序所需的内容并实现方法来做到这一点,仅此而已。将System.Entity的功能带到DAL之外没有什么意义,它们应该在客户端层面抽象出来。

我讨厌的一件事是,如果我想让我的服务/上下文层远离应用程序的其他部分,则必须复制模型。为了解决这个问题,我有一个模型工厂,它使用DI来找到EF模型并通过DI容器交付。这只意味着我必须为我创建的每个模型添加一个接口。没什么大不了的。