通用存储库模式有重复的代码,所以会有什么好处
本文关键字:什么 代码 存储 模式 | 更新日期: 2023-09-27 18:15:42
我正在理解c#中的存储库模式。当我研究通用存储库模式时,我感到困惑。里面有很多重复的地方。我对这种式样有一些疑问。
我使用实体框架代码第一方法,我有两个模型类
老师
我将使用多少个泛型接口,例如,如果我有一个通用接口
public interface IRepository<TEntity>
{
IQueryable<TEntity> FindAll(Expression<Func<TEntity, bool>> where = null);
TEntity FindOne(Expression<Func<TEntity, bool>> where = null);
}
所以这个接口可以在两个模型类中使用。如果学生类有更多的方法,我可以定义这些方法?例如
public class StudentRepo<TEntity> : IRepository<TEntity> where TEntity : class
{
public virtual IQueryable<TEntity> FindAll(Expression<Func<TEntity, bool>> where = null)
{
return null != where ? Context.Set<TEntity>().Where(where) : Context.Set<TEntity>();
}
public virtual TEntity FindOne(Expression<Func<TEntity, bool>> where = null)
{
return FindAll(where).FirstOrDefault();
}
public void update()
{
}
public int FindId()
{
}
}
所以我在StudentRepo
中添加了两个新方法update()
和FindId()
,我可以在哪里定义这些方法?
如果我想在IRepository
中添加这两个方法,那么我必须为Teacher类调用这些方法。它的好处是什么?如果我为两个类创建单独的接口,这是更好的方法吗?像IStudent和itacher,所以我可以定义那些我想使用的方法和不必要的方法将不会在使用。
请引导我,我很困惑
您可以有一个IRepository
的实现,如:
public class GenericRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
public virtual IEnumerable<TEntity> FindAll(Expression<Func<TEntity, bool>> where = null)
{
// implementation ...
}
public virtual TEntity FindOne(Expression<Func<TEntity, bool>> where = null)
{
// implementation
}
public void Update(TEntity entity)
{
// update your entity ...
}
// etc...
}
然后从它继承你自己的存储库:
public class StudentRepository : GenericRepository<Student>
{
// here you get all the goodies + you can add your own stuff
}
:
public class TeacherRepository : GenericRepository<Teacher>
{
// here you get the same goodies, you don't need to re-implement them
}
通过这种方式,您不必重新实现通用存储库中定义的所有方法,但是您可以添加自己的更复杂的方法。
通用存储库毫无价值。它们只是做同样的事情作为实体框架和大多数的实现在那里暴露IQueryable<T>
。
为什么这么糟糕呢?
存储库模式用于在数据源和代码之间创建抽象。创建该抽象是为了降低复杂性,并减少这些层之间的耦合。
通用存储库一开始似乎是一个不错的选择,但由于每个实体(根聚合)都有自己独特的功能,您将始终必须编写自定义查询来获取它们。
为了解决这个问题,大多数通用实现都公开了IQueryable<T>
。这是一件坏事,因为没有100%完整的Linq to Sql提供程序(一组将Linq语句转换为Sql语句的类)。每个提供者都必须求助于自定义命令来支持渴望/延迟加载,支持IN
sql子句等。
每次通过IQueryable<T>
使用存储库时,都必须注意这些自定义。
因此你仍然需要知道实体框架是如何工作的。因此,您可以直接使用EF而不是使用通用存储库。
如果你真的想使用存储库模式,请先用你所有的类来设计你的代码。然后创建数据库。也就是说,在代码之后适合数据库,而不是相反。并确保您的存储库是100%完整的抽象(例如google persistance ignorance
)
我认为通用存储库的想法太一般化了,在我看来,单独的接口更好,因为它们提供了更有意义的契约,这个博客解释得很好,并提供了在"幕后"使用通用存储库。