实体框架与存储库模式

时间:2014-06-15 16:39:42

标签: c# entity-framework

我想知道使用Entity Framework在项目中存储库模式的有用性。对此有相反的说法 - 有人说EF是存储库和工作单元模式本身的实现,所以没有必要将它包装在下一个抽象层中,有些人认为它具有分离DAL和BL以及更容易创建的优点单元测试根据我的经验,我经常遇到以下方法(通常不仅在EF项目中):

Repository (DAL) <-> Service (BL) <-> Controller

Repository + Service + Type = Model

存储库只有负责数据访问的方法,即:

public interface IUsersRepository
{
  IEnumerable<User> GetAll();
  User Get(int id);
  User GetByLogin(string login);
  void Update(User item);
  void Delete(int id);
  void Delete(User item);
  // ...
}

通常,使用通用存储库,哪些方法接收过滤,排序等功能。

服务反过来使用存储库并包含业务逻辑,即:。

public interface IUsersService
{
  // ...
  bool VerifyPassword(string login, string password);
  void ChangePassword(string login, string password);
  // ...
}

据我所知,服务不应该有任何DAL操作 - 这意味着我们不应该从存储库返回IQueryable集合,因为然后查询将在存储库外执行,单元测试将不完全可靠(LINQ之间的差异) -to-Entities和LINQ-to-Objects)。

我发现这里的查询效率存在问题 - 我们经常从数据库中获取比需要更多的数据,然后在内存中过滤它。

例如,让我们考虑 bool VerifyPassword(字符串登录,字符串密码)方法。

在这种情况下,我们需要从数据库中获取整个User实体,例如,可以有50个属性,仅用于密码验证。当然,我们可以在存储库中创建许多方法,如:

string GetPasswordHash(string login) 

bool VerifyPassword(string login, string passwordHash) 
{
  return db.Users.Any(x => x.Login = login && x.Password = passwordHash);
} 

无需从数据库中获取整个实体,但在我看来,这可能是一个“小”开销。

我们还可以将VerifyPassword函数从服务移动到存储库 - 然后我们应该问自己一个问题是否需要两个层 - 存储库和服务。但是如果我们合并它们,我们将失去分离DAL和BL层的好处 - 单元测试将是现实中的集成测试。所以也许将它全部保存在控制器中并注入模拟的DbContext或使用像Effort这样的单元测试会更简单(也更好)?

我将非常感谢您的答案,您如何看待这个以及如何在项目中解决这个问题。

更新

据我所知,存储库模式允许轻松地将数据源/提供程序更改为其他类似nHibernate,LINQ-to-SQL,普通ADO等。

但是,您能告诉我如何在存储库API中实现排序和分页?我的意思是将排序和分页规范传递给存储库的最佳方法是什么?我看到一些传递函数谓词用于LINQ,但这会将存储库与LINQ紧密耦合 - 将它与普通的ADO,存储过程等一起使用会有问题。在我看来,创建GetUsersOrderedByNameDesc()等许多方法都很疯狂。那么可能为规范,伪造和传递排序/分页标准创建自己的类,并在存储库中处理它?如果是的话,你能给我一些实施的例子吗?

1 个答案:

答案 0 :(得分:0)

我会尝试尝试你的核心问题。这是我的两分钱。 为什么存储库与实体框架。在设计或挑选哪一个问题时,您需要回答我建议您提出的一些问题:

  1. 您的项目是否有可能会有不同的存储库?如果是,那么实体框架上的存储库模式是有意义的。
  2. 拥有存储库模式还允许您更轻松地设置测试框架,您可以使用存储库模式(DAL)将使用的模型数据库。
  3. 您可能还希望考虑对数据模型的更改可以使用实体框架渗透回业务逻辑中的更改。