C# 使用EntityFramework设计模式?
接口C# 使用EntityFramework设计模式?,c#,entity-framework,design-patterns,C#,Entity Framework,Design Patterns,接口 public interface IDinnerRepository { IQueryable<Dinner> FindAllDinners(); IQueryable<Dinner> FindDinnersByText(string q); Dinner GetDinner(int id); void Add(Dinner dinner); void Delete(Dinner dinner); void S
public interface IDinnerRepository
{
IQueryable<Dinner> FindAllDinners();
IQueryable<Dinner> FindDinnersByText(string q);
Dinner GetDinner(int id);
void Add(Dinner dinner);
void Delete(Dinner dinner);
void Save();
}
而且不使用存储库设计模式
public class DinnerOperation
{
DinnerEntities entity = new DinnerEntities();
// insert
public void InsertDinner()
{
Dinner dinner = entity.Dinners.Find(5);
entity.Dinner.Add(dinner);
entity.SaveChanges();
}
// delete
public void DeleteDinner()
{
Dinner dinner = entity.Dinners.Find(5);
entity.Dinner.Remove(dinner);
entity.SaveChanges();
}
}
问题:
我不明白,在这里,我们为什么要使用设计模式?
以这种方式将存储库设计模式与实体框架结合使用并不意味着什么
如何将设计模式与entitiy framework结合使用?什么时候将设计模式与实体框架结合使用才有意义?这是存储库模式,它本身就是实体框架的超级模式,因为
DbContext
同时充当存储库和工作单元,但它是不可模仿的-没有IDbContext
。因此,您最终将DbContext
放在一个精简的存储库包装器中,以便以后可以轻松地测试组件
我认为值得一提的是,我从未在NHibernate中使用过存储库模式,因为会话和会话工厂是接口-ISession
和ISessionFactory
如果您在某处(IRepository
)按接口使用存储库并将其注入,则通过模拟/存根进行测试将更容易:
public class DinnerOperation
{
private readonly IDinnerRepository repository;
public DinnerOperation(IDinnerRepository dinnerRepository)
{
repository = dinnerRepository;
}
}
当然,您必须使用所选的IoC容器为您注入正确的实例(DinnerRepository
,在本例中),或者手动执行DI
这样,您就可以针对模拟或存根存储库测试
dinnerooperation
类。当您实例化DbContext
时,您不能这样做。您几乎得到了它。首先,重构晚餐操作类,以便将存储库实现注入其中
public class DinnerOperation
{
private IDinnerRepository dr;
public DinnerOperation( IDinnerRespository repository ) {
this.dr = repository;
}
// insert
public void InsertDinner()
{
Dinner dinner = dr.GetDinner(5);
dr.Dinner.Add(dinner);
dr.Save();
}
// delete
public void DeleteDinner()
{
Dinner dinner = dr.GetDinner(5);
dr.Dinner.Delete(dinner);
dr.Save();
}
}
然后实现不同的存储库:
public class EntityFrameworkDinnerRepository : IDinnerRepository
public class NHibernateDinnerRepository : IDinnerRepository
public class Linq2SqlDinnerRepository : IDinnerRepository
public class MockDinnerRepository : IDinnerRepository
....
然后使用您想要的任何存储库:
var repository = new ....Repository();
var operation = new DinnerOperation( repository );
operation.GetDinner(5);
存储库用于抽象您的具体数据提供者,从而使您的体系结构更加合适
想换成nHibernate吗
如果到处都有EntityFramework,那就很痛苦。
很简单,如果您使用存储库,只需注入另一个存储库,您的业务逻辑就不必更改
想要单元测试您的业务逻辑吗
如果你坚持使用一个具体的数据提供者,那会很痛苦。
很简单,如果您有存储库,只需注入一个inmemory存储库,它甚至不使用数据库
现在明白了吗?当我使用ORM时,我拒绝使用存储库模式。我认为在这种情况下,它几乎没有什么好处。(是的,我预计会被狂热者投下2000票) 使用EF,我为我的上下文创建了一个接口
public interface IDinnerContext : IDisposable
{
IDbSet<Dinner> Dinners;
int SaveChanges();
}
公共接口IDinerContext:IDisposable
{
套餐;
int SaveChanges();
}
然后,我将这个接口粘贴在我的EF DatabaseContext实现上,还有viola!我可以在任何地方使用EF,通过模拟实现对我的db访问进行单元测试,如果我愿意,可以使用注入,而不是使用600万个GetByXXX方法。IQeryable处理了,我的执行被延迟了。我并不真正需要Insert/Delete方法,因为IDBSet已经有了Add/Remove。我的代码更清晰/更容易阅读,抽象更少
如果我确实有一个案例,在许多不同的地方使用相同的查询,并且我真的希望这是常见的,那么我可以添加一些机制来支持这一点。然而,95%的情况下,查询特定于负责业务逻辑X的组件(简单GetBy语句之外的任何内容)。所以我不认为这是个问题
别误会,在ORMs变得相当不错之前,我一直虔诚地使用存储库模式。一旦ORMs达到了一定的成熟度,我觉得可能不再需要存储库模式,于是开始在没有它的情况下进行项目。。。。而且从未回头。我认为其他所有人最终都会朝着这个方向走,或者类似的方向走,但旧习惯的消亡需要一段时间。(我知道一些开发人员仍然坚持使用锁(这个),因为它仍然存在于一些MS示例中)。非常感谢。有很多东西要学:)。是否有任何教程、文章等。。。关于这个话题。我差点就明白了。为了更好地理解,你有什么建议吗?我不记得有任何简明而完整的资料来源。只需在“Repository pattern explained”上用谷歌搜索一下,再多读几篇教程,研究一下与Repository模式配合得很好的依赖注入模式。从EF切换到NH或内存中的提供者或其他任何东西都不“容易”使用一个公开
IQueryable
@Slauma的存储库:这非常简单,因为类库包含IEnumerables上的AsQueryable扩展方法。NH还支持linq。我为linq2sql、nhibernate、ef、xpo和内存实现了存储库,它们都实现了相同的接口。是的,NH支持LINQ,但与ef(LINQ到实体)不同,LINQ到实体不是LINQ到对象,也不是LINQ到SQL。您可以使用相同的LINQ代码,所有代码都可以编译,但一个可以工作,另一个不能工作,或者其行为不同。它依赖于提供程序,如果使用提供程序2的代码正常工作,则无法使用使用提供程序1的代码进行测试。这里更好地解释了我的意思:(包括答案末尾的链接)。+1。另一种观点。在你回答之后,我有点困惑。我认为,在决定使用哪一种时,需要经验。这给了我继续编码的士气。非常感谢……嗯,我想我在那里对人们理解/知道的东西做了一些假设。人们坚持使用存储库模式有两个主要原因。1) 单元测试,2)查询重用。单元测试现在很容易在EF和IDbContext中进行。查询重用也可以处理,尽管我相信通过组件驱动的开发,组件之间的实际查询使用几乎没有重叠,所以您只需要在组件级别进行管理,这很容易做到……但我还是更喜欢利用EF/IQueryable的灵活性。实体框架是可模拟的。。。。现在。你是
var repository = new ....Repository();
var operation = new DinnerOperation( repository );
operation.GetDinner(5);
public interface IDinnerContext : IDisposable
{
IDbSet<Dinner> Dinners;
int SaveChanges();
}