我想知道使用实体框架的项目中存储库模式的用处。对此有相反的说法 - 有人说EF是存储库和工作单元模式本身的实现,所以不需要将其包装在下一个抽象层中,有人认为它具有诸如DAL和BL分离以及更容易创建等优点的单元测试。根据我的经验,我经常遇到以下的方法(一般,不仅在EF项目):实体框架vs存储库模式
Repository (DAL) <-> Service (BL) <-> Controller
Repository + Service + Type = Model
Repository有只负责数据访问,即方法:
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(字符串登录,字符串密码)方法。
在这种情况下,我们需要从数据库中获取整个用户实体,例如,可以有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这样的单元测试?
我将非常感谢您的回答,您如何看待这一情况以及如何在您的项目中解决此问题。
UPDATE
我明白,存储库模式允许容易地改变像的nHibernate数据源/提供者以外,LINQ到SQL,平原ADO等。
但是你能告诉我你如何在你的仓库API中实现排序和分页吗?我的意思是将排序和分页规范传递给存储库的最佳方式是什么?我看到有些函数为LINQ函数使用了谓词,但是这会将存储库与LINQ紧密结合 - 使用它与纯ADO,存储过程等将会产生问题。创建像GetUsersOrderedByNameDesc()等许多方法在我看来是疯狂的。所以也许创建自己的规范类,伪造和传递排序/分页标准,并在库中处理它?如果是的话,你能给我提供一些实现的例子吗?
我不确定实际问题是什么,所以这是一个评论,而不是让你更具体的答案。当然,这是一个不错的主意,它拥有存储库层和单独的服务层。提到的VerifyPassword是一个很好的服务方法的候选者,它只会在存储库语言而不是DAL语言中实现。 –
我不同意,但没关系。它只是表明这个问题对于StackOverflow的Q&A格式来说太广泛了。 –