我正在学习存储库模式,正在阅读Repository Pattern with Entity Framework 4.1 and Code First 和Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle ,了解它们如何使用Entity Framework实现存储库模式。
说
•从上层隐藏EF •使代码更易于测试
使代码更易于测试我理解,但为什么要将EF隐藏在上层?
看看它们的实现,似乎只是用实体方法包装实体框架来查询实体框架。实际上是这样做的原因是什么?
我假设是
我理解正确吗?
如果我写一个DataAccessLayer,这是一个有方法的类
QueryFooObject(int id)
{
..//query foo from entity framework
}
AddFooObject(Foo obj)
{
.. //add foo to entity framework
}
......
QueryBarObject(int id)
{
..
}
AddBarObject(Bar obj)
{
...
}
这也是一个存储库模式吗?
假人的解释会很棒:)
答案 0 :(得分:63)
我认为你不应该这样做。
实体框架已经是数据库的抽象层。上下文使用工作单元模式,每个DBSet都是一个存储库。在此基础上添加存储库模式可使您远离ORM的功能。
我在博客文章中谈过这个问题: http://www.nogginbox.co.uk/blog/do-we-need-the-repository-pattern
添加自己的存储库实现的主要原因是您可以使用依赖注入并使代码更易于测试。
EF开箱即用并不是非常容易测试,但是使用可以注入的接口制作EF数据上下文的可模拟版本非常容易。
我在这里谈到了: http://www.nogginbox.co.uk/blog/mocking-entity-framework-data-context
如果我们不需要存储库模式来使EF可测试,那么我认为我们根本不需要它。
答案 1 :(得分:8)
有一件事是增加可测试性并与基础持久性技术松散耦合。但是每个聚合根对象也有一个存储库(例如,一个订单可以是一个聚合根,它也有订单行(不是聚合根),以使域对象持久性更加通用。
它还使管理对象变得更加容易,因为当您保存订单时,它还会保存您的子项(可以是订单行)。
答案 2 :(得分:6)
答案 3 :(得分:4)
将查询置于中心位置也是一个优势;否则你的查询会分散在各处,并且难以维护。
你提到的第一点:“隐藏EF”是一件好事!例如,保存逻辑可能很难实现。有多种策略适用于不同的场景。特别是在涉及相关实体也有变化的储蓄实体时。
使用存储库(与UnitOfWork结合使用)也可以集中这个逻辑。
Here是一些有很好解释的视频。
答案 4 :(得分:3)
存储库系统适合进行测试。
一个原因是您可以使用依赖注入。
基本上,您为存储库创建了一个接口,并在创建对象时引用它的接口。然后,您可以稍后创建一个伪对象(例如使用moq)来实现该接口。使用像ninject这样的东西,然后你可以将正确的类型绑定到该接口。你只是从等式中取出了一个依赖,并用可测试的东西取而代之。
我们的想法是能够轻松交换对象的实现以进行测试 希望这是有道理的。
答案 5 :(得分:0)
您在应用中没有硬编码文件路径的原因相同:loose coupling和encapsulation。想象一下一个应用程序,其中包含对“c:\ windows \ fonts”的硬编码引用以及可能导致的问题。您不应该硬编码对路径的引用,那么为什么要硬编码对持久层的引用?隐藏配置设置(或special folders或OS支持的任何内容)后面的路径,并隐藏存储库后面的持久性。如果持久性问题隐藏在存储库后面,则可以更轻松地进行单元测试,部署到其他环境,交换实现以及推理域对象。
答案 6 :(得分:0)
当您设计存储库类以查找相似的域对象,为所有存储库提供相同的数据上下文并促进工作单元的实现时,存储库模式是有意义的。请在下面找一些人为的例子。
class StudenRepository
{
dbcontext ctx;
StundentRepository(dbcontext ctx)
{
this.ctx=ctx;
}
public void EnrollCourse(int courseId)
{
this.ctx.Students.Add(new Course(){CourseId=courseId});
}
}
class TeacherRepository
{
dbcontext ctx;
TeacherRepository(dbcontext ctx)
{
this.ctx=ctx;
}
public void EngageCourse(int courseId)
{
this.ctx.Teachers.Add(new Course(){CourseId=courseId});
}
}
public class MyunitOfWork
{
dbcontext ctx;
private StudentRepository _studentRepository;
private TeacherRepository _teacherRepository;
public MyunitOfWork(dbcontext ctx)
{
this.ctx=ctx;
}
public StudentRepository StundetRepository
{
get
{
if(_studentRepository==null)
_stundentRepository=new StundetRepository(this.ctx);
return _stundentRepository;
}
}
public TeacherRepository TeacherRepository
{
get
{
if(_teacherRepository==null)
_teacherRepository=new TeacherRepository (this.ctx);
return _teacherRepository;
}
}
public void Commit()
{
this.ctx.SaveChanges();
}
}
//some controller method
public void Register(int courseId)
{
using(var uw=new MyunitOfWork(new context())
{
uw.StudentRepository.EnrollCourse(courseId);
uw.TeacherRepository.EngageCourse(courseId);
uw.Commit();
}
}
答案 7 :(得分:0)
我知道这里提供的链接很糟糕,但是想要与Entity框架一起使用时,想要分享解释Repository Pattern各种优点的视频。以下是youtube的链接。
https://www.youtube.com/watch?v=rtXpYpZdOzM
它还提供了有关如何正确实现存储库模式的详细信息。