C# 实体框架-如何使用自定义DbContext实现存储库?

C# 实体框架-如何使用自定义DbContext实现存储库?,c#,entity-framework,repository,dbcontext,C#,Entity Framework,Repository,Dbcontext,我们开始在公司开发一个小框架,在不同的应用程序之间共享代码。对于数据访问,我们使用EF4。我们有一个自定义DbContext类和一个通用存储库: public class RMDbContext : DbContext { // .... } public interface IRepository { IQueryable<T> All(); void Delete(T entity) where T : class; void Add(T en

我们开始在公司开发一个小框架,在不同的应用程序之间共享代码。对于数据访问,我们使用EF4。我们有一个自定义DbContext类和一个通用存储库:

public class RMDbContext : DbContext
{
    // ....
}

public interface IRepository 
{
    IQueryable<T> All();
    void Delete(T entity) where T : class;
    void Add(T entity) where T : class;
    void Update(T entity) where T : class;
    int SaveChanges();
    void RollbackChanges();
}
public abstract class BaseRepository<TModel, TEntities> where TEntities : IDbSet<TModel>
{
    protected TEntities Entities {get; set;}
    protected DbContext Db {get; set;}

    public BaseRepository (DbContext db, TEntities entities)
    {
        Db = db;
        Entities = entities;
    }

    public virtual TModel Create() { return Entities.Create (); }
    public virtual TModel Retrieve (params object[] keys) { return Entities.Find (keys); }
    public virtual void Update (TModel existing) { Db.Entry(existing).State = Modified; }
    public virtual void Delete (TModel existing) { Db.Entry(existing).State = Removed; }
}
老实说,我不喜欢这种方法,因为上下文与特定的合同(IRepository)有关。在我看来,最好创建一个使用RMDbContext的存储库实现,如下所示:

public class Repository<T> : IRepository where T : RMDbContext, new()
{
    protected readonly RMDbContext context;

    public class Repository()
    {
         context = new T();
    }

    // ....
}
interface ICRUD<T> : ICreatable<T>, IRetrievable<T>, IUpdatable<T>, IDeletable<T>
{
}

interface ICreatable<T>
{
    T Create();
}

interface IRetrieve<T>
{
    T Retrieve(params object[] keys);
}

interface IUpdatable<T>
{
    void Update(T existing);
}

interface ICreatable<T>
{
    void Delete(T existing);
}
公共类存储库:IRepository,其中T:RMDbContext,new() { 受保护的只读RMDbContext上下文; 公共类存储库() { 上下文=新的T(); } // .... }
您对这两种方法有何看法?你会选择哪一个,为什么?

我个人鼓励你们不要创建任何东西,只需使用dbContext,它有所有你需要的方法

我自己实现了#1(实现了IRepository),但您最终会进行一些时髦的编程,以获得正确的ObjectSet或EntitySet,以便从add/delete方法中添加或删除


当您在objectmodel中添加继承层次结构时,该代码将变得越来越复杂。

我个人鼓励大家不要创建任何东西,只需使用dbContext,它拥有您需要的所有方法

我自己实现了#1(实现了IRepository),但您最终会进行一些时髦的编程,以获得正确的ObjectSet或EntitySet,以便从add/delete方法中添加或删除


随着您在objectmodel中添加继承层次结构,该代码将变得越来越复杂。

首先,您不应该将存储库与RMDbContext紧密耦合,因为这是一种糟糕的设计味道,您应该始终使用接口

第二,存储库不应实现IRMDbContext接口(如果存在),因为存储库不需要它。您应该使用它,而不是实现它,因此如果您创建存储库,最好在其构造函数中使用IRMDbContext参数,如下所示

公共类存储库 {

以及工作类的单元,即实例化上下文并将其发送到存储库的单元,请参见以下链接


首先,您不应该将存储库与RMDbContext紧密耦合,因为这是一种糟糕的设计味道,您应该始终使用接口

第二,如果存在IRMDbContext接口,则存储库不应实现它,因为存储库不需要它。您应该使用它,而不是实现它,因此创建存储库时最好在其构造函数中使用IRMDbContext参数,如下所示

公共类存储库 {

以及工作类的单元,即实例化上下文并将其发送到存储库的单元,请参见以下链接


我们在工作中所做的就是实现这样一种模式:

public class Repository<T> : IRepository where T : RMDbContext, new()
{
    protected readonly RMDbContext context;

    public class Repository()
    {
         context = new T();
    }

    // ....
}
interface ICRUD<T> : ICreatable<T>, IRetrievable<T>, IUpdatable<T>, IDeletable<T>
{
}

interface ICreatable<T>
{
    T Create();
}

interface IRetrieve<T>
{
    T Retrieve(params object[] keys);
}

interface IUpdatable<T>
{
    void Update(T existing);
}

interface ICreatable<T>
{
    void Delete(T existing);
}
接口ICRUD:ICreatable、IRETREABLE、IUpdatable、IDeletable
{
}
界面可重复
{
T Create();
}
接口IRetrieve
{
T检索(参数对象[]键);
}
接口IUpdatable
{
无效更新(T现有);
}
界面可重复
{
无效删除(T现有);
}
然后我们创建了一个以实体为基础的存储库:

public class RMDbContext : DbContext
{
    // ....
}

public interface IRepository 
{
    IQueryable<T> All();
    void Delete(T entity) where T : class;
    void Add(T entity) where T : class;
    void Update(T entity) where T : class;
    int SaveChanges();
    void RollbackChanges();
}
public abstract class BaseRepository<TModel, TEntities> where TEntities : IDbSet<TModel>
{
    protected TEntities Entities {get; set;}
    protected DbContext Db {get; set;}

    public BaseRepository (DbContext db, TEntities entities)
    {
        Db = db;
        Entities = entities;
    }

    public virtual TModel Create() { return Entities.Create (); }
    public virtual TModel Retrieve (params object[] keys) { return Entities.Find (keys); }
    public virtual void Update (TModel existing) { Db.Entry(existing).State = Modified; }
    public virtual void Delete (TModel existing) { Db.Entry(existing).State = Removed; }
}
公共抽象类BaseRepository,其中tenties:IDbSet
{
受保护的实体{get;set;}
受保护的DbContext数据库{get;set;}
公共BaseRepository(DbContext数据库、TEntities实体)
{
Db=Db;
实体=实体;
}
公共虚拟TModel Create(){return Entities.Create();}
公共虚拟TModel检索(params对象[]键){返回实体。查找(键);}
公共虚拟无效更新(TModel现有){Db.Entry(现有).State=Modified;}
公共虚拟void Delete(TModel现有){Db.Entry(现有).State=Removed;}
}

如果您注意到,BaseRepository实际上没有使用ICRUD,只是具有相同的方法签名。由于我们对接口进行编码,这使我们可以使用大量共享代码,而不会暴露我们不希望使用基类的功能。开发人员可以自由地实现数据存储,无论他们希望如何(例如,ICRUD可以与Web服务对话)不了解实体,或者他们也可以通过覆盖提供的任何方法和做一些不同的事情来自由扩展BaseRepository提供的行为。

我们在工作中所做的是实现这样一种模式:

public class Repository<T> : IRepository where T : RMDbContext, new()
{
    protected readonly RMDbContext context;

    public class Repository()
    {
         context = new T();
    }

    // ....
}
interface ICRUD<T> : ICreatable<T>, IRetrievable<T>, IUpdatable<T>, IDeletable<T>
{
}

interface ICreatable<T>
{
    T Create();
}

interface IRetrieve<T>
{
    T Retrieve(params object[] keys);
}

interface IUpdatable<T>
{
    void Update(T existing);
}

interface ICreatable<T>
{
    void Delete(T existing);
}
接口ICRUD:ICreatable、IRETREABLE、IUpdatable、IDeletable
{
}
界面可重复
{
T Create();
}
接口IRetrieve
{
T检索(参数对象[]键);
}
接口IUpdatable
{
无效更新(T现有);
}
界面可重复
{
无效删除(T现有);
}
然后我们创建了一个以实体为基础的存储库:

public class RMDbContext : DbContext
{
    // ....
}

public interface IRepository 
{
    IQueryable<T> All();
    void Delete(T entity) where T : class;
    void Add(T entity) where T : class;
    void Update(T entity) where T : class;
    int SaveChanges();
    void RollbackChanges();
}
public abstract class BaseRepository<TModel, TEntities> where TEntities : IDbSet<TModel>
{
    protected TEntities Entities {get; set;}
    protected DbContext Db {get; set;}

    public BaseRepository (DbContext db, TEntities entities)
    {
        Db = db;
        Entities = entities;
    }

    public virtual TModel Create() { return Entities.Create (); }
    public virtual TModel Retrieve (params object[] keys) { return Entities.Find (keys); }
    public virtual void Update (TModel existing) { Db.Entry(existing).State = Modified; }
    public virtual void Delete (TModel existing) { Db.Entry(existing).State = Removed; }
}
公共抽象类BaseRepository,其中tenties:IDbSet
{
受保护的实体{get;set;}
受保护的DbContext数据库{get;set;}
公共BaseRepository(DbContext数据库、TEntities实体)
{
Db=Db;
实体=实体;
}
公共虚拟TModel Create(){return Entities.Create();}
公共虚拟TModel检索(params对象[]键){返回实体。查找(键);}
公共虚拟无效更新(TModel现有){Db.Entry(现有).State=Modified;}
公共虚拟void Delete(TModel现有){Db.Entry(现有).State=Removed;}
}
如果您注意到,BaseRepository实际上没有使用ICRUD,只是具有相同的方法签名。由于我们对接口进行编码,这使我们可以使用大量共享代码,而不会暴露我们不希望使用基类的功能。开发人员可以自由地实现数据存储,无论他们希望如何(例如,ICRUD可以与Web服务对话)不了解实体,或者他们也可以通过覆盖提供的任何方法和执行不同的操作来自由扩展BaseRepository提供的行为