C#存储库设计问题

C#存储库设计问题,c#,inheritance,abstract-class,repository-pattern,C#,Inheritance,Abstract Class,Repository Pattern,我正在为MVC2Web应用程序编写一个EF4数据层,我需要关于选择继承还是抽象基类的建议。我的存储库按照“通用回购”结构运行良好,但现在我想添加“审计”功能,记录每次执行CRUD操作的情况 这是我到目前为止一直使用的合同: public interface IRepository<T> { void Create(T entity); void Update(T entity); void Delete(Func<T, bool> predicat

我正在为MVC2Web应用程序编写一个EF4数据层,我需要关于选择继承还是抽象基类的建议。我的存储库按照“通用回购”结构运行良好,但现在我想添加“审计”功能,记录每次执行CRUD操作的情况

这是我到目前为止一直使用的合同:

public interface IRepository<T>
{
    void Create(T entity);
    void Update(T entity);
    void Delete(Func<T, bool> predicate);
    T Get(Func<T, bool> predicate);
    IQueryable<T> Query();
}
公共接口IRepository
{
无效创建(T实体);
无效更新(T实体);
无效删除(Func谓词);
T Get(Func谓词);
IQueryable查询();
}
我的回购协议。实现如下所示:

sealed class EFRepository<TEntity> : IRepository<TEntity>
    where TEntity : EntityObject
{
    ObjectContext _context;
    ObjectSet<TEntity> _entitySet;

    public EFRepository(ObjectContext context)
    {
        _context = context;
        _entitySet = _context.CreateObjectSet<TEntity>();
    }

    public void Create(TEntity entity)
    {
        _entitySet.AddObject(entity);
        _context.SaveChanges();
    }

    public void Update(TEntity entity)
    {
        _entitySet.UpdateObject(entity);
        _context.SaveChanges();
    }

    public void Delete(Func<TEntity, bool> predicate)
    {
        TEntity entity = _entitySet.Single(predicate);
        _entitySet.DeleteObject(entity);
        _context.SaveChanges();
    }

    public TEntity Get(Func<TEntity, bool> predicate)
    {
        return _entitySet.SingleOrDefault(predicate);
    }

    public IQueryable<TEntity> Query()
    {
        return _entitySet;
    }
}
interface IAuditable<T>
interface IRepository<T>
AuditableRepository<T> : IRepository<T>, IAuditable<T>
EFRepository<T> : AuditableRepository<T>
interface IAuditable<T>
interface IRepository<T>
EFRepository<T> : IRepository<T>, IAuditable<T>
密封类eRepository:IRepository
其中tenty:EntityObject
{
ObjectContext _context;
ObjectSet _entitySet;
公共eForepository(ObjectContext上下文)
{
_上下文=上下文;
_entitySet=_context.CreateObjectSet();
}
公共void创建(TEntity实体)
{
_entitySet.AddObject(实体);
_SaveChanges();
}
公共无效更新(TEntity实体)
{
_entitySet.UpdateObject(实体);
_SaveChanges();
}
公共void Delete(Func谓词)
{
TEntity entity=_entitySet.Single(谓词);
_entitySet.DeleteObject(实体);
_SaveChanges();
}
公共TEntity Get(Func谓词)
{
返回_entitySet.SingleOrDefault(谓词);
}
公共IQueryable查询()
{
返回_entitySet;
}
}
我想创建一个
AuditableRepository
的概念。我应该这样创建它:

sealed class EFRepository<TEntity> : IRepository<TEntity>
    where TEntity : EntityObject
{
    ObjectContext _context;
    ObjectSet<TEntity> _entitySet;

    public EFRepository(ObjectContext context)
    {
        _context = context;
        _entitySet = _context.CreateObjectSet<TEntity>();
    }

    public void Create(TEntity entity)
    {
        _entitySet.AddObject(entity);
        _context.SaveChanges();
    }

    public void Update(TEntity entity)
    {
        _entitySet.UpdateObject(entity);
        _context.SaveChanges();
    }

    public void Delete(Func<TEntity, bool> predicate)
    {
        TEntity entity = _entitySet.Single(predicate);
        _entitySet.DeleteObject(entity);
        _context.SaveChanges();
    }

    public TEntity Get(Func<TEntity, bool> predicate)
    {
        return _entitySet.SingleOrDefault(predicate);
    }

    public IQueryable<TEntity> Query()
    {
        return _entitySet;
    }
}
interface IAuditable<T>
interface IRepository<T>
AuditableRepository<T> : IRepository<T>, IAuditable<T>
EFRepository<T> : AuditableRepository<T>
interface IAuditable<T>
interface IRepository<T>
EFRepository<T> : IRepository<T>, IAuditable<T>
接口IAuditable
界面假定
AuditableRepository:IRepository,IAuditable
eRepository:AuditableRepository
还是这样比较好:

sealed class EFRepository<TEntity> : IRepository<TEntity>
    where TEntity : EntityObject
{
    ObjectContext _context;
    ObjectSet<TEntity> _entitySet;

    public EFRepository(ObjectContext context)
    {
        _context = context;
        _entitySet = _context.CreateObjectSet<TEntity>();
    }

    public void Create(TEntity entity)
    {
        _entitySet.AddObject(entity);
        _context.SaveChanges();
    }

    public void Update(TEntity entity)
    {
        _entitySet.UpdateObject(entity);
        _context.SaveChanges();
    }

    public void Delete(Func<TEntity, bool> predicate)
    {
        TEntity entity = _entitySet.Single(predicate);
        _entitySet.DeleteObject(entity);
        _context.SaveChanges();
    }

    public TEntity Get(Func<TEntity, bool> predicate)
    {
        return _entitySet.SingleOrDefault(predicate);
    }

    public IQueryable<TEntity> Query()
    {
        return _entitySet;
    }
}
interface IAuditable<T>
interface IRepository<T>
AuditableRepository<T> : IRepository<T>, IAuditable<T>
EFRepository<T> : AuditableRepository<T>
interface IAuditable<T>
interface IRepository<T>
EFRepository<T> : IRepository<T>, IAuditable<T>
接口IAuditable
界面假定
eRepository:IRepository,iAudible
甚至:

interface IAuditable<T>
interface IRepository<T>
AuditableRepository<T> : IRepository<T>, IAuditable<T>
EFRepository<T> : IRepository<T>
AuditableEFRepository<T> : AuditableRepository<T>
接口IAuditable
界面假定
AuditableRepository:IRepository,IAuditable
eRepository:IRepository
AuditableRepository:AuditableRepository

并非我所有的电子邮箱都需要审核。如何继续?

还有一种可能性(使用Decorator对象向现有存储库添加其他功能):

public sealed类审核员:IRepository
{
专用只读IRepository存储库;
公共审计师(IRepository repository)
{
_存储库=存储库;
}
公共无效创建(T实体)
{
//在这里审计。。。
_创建(实体);
}
//等其他方法。。。
}

使用Decorator添加附加功能的优点是,它避免了当您考虑一些存储库进行审计时,您开始看到的组合爆炸,有些没有,有些使用EF,有些没有。每一个可能应用或可能不应用的新特性都会使情况变得越来越糟,最终往往会演变为配置标志和混乱的内部分支。

这两种方法都不是完美的解决方案,正如Dan所说,不同的接口组合可能会带来问题。审计功能听起来也不是真的需要成为类的一部分。我认为,我不会采用Dan的方法,而是会在存储库中声明和触发事件。这样你就可以把很多不同的东西连接起来,更加灵活。因此,请声明创建、删除等事件


将来,它还可以通过诸如反应式扩展之类的方式提供一些非常好的功能

首先,如果您的
存储库
没有任何公共功能(您只有抽象方法,没有实现),那么我要做的第一件事就是去掉它。最好您的程序的所有其他部分只通过
IRepository
界面访问存储库,这将给您以后更大的自由度

第二件事,拥有一个
eRepository
类意味着您希望在某一天留下一个切换到不同ORM的选项。我的意见是——不要这样做。如果选择EF,请坚持EF。如果您真的认为这是一个选项,那么至少创建一个具有名称空间
MyApp.EntityORM
或其他名称空间的单独程序集,将所有存储库类放在那里,并去掉
EF
前缀。然后,如果真是这样,也许有一天您可以通过依赖项注入加载正确的ORM,而无需更改其余代码

根据我的经验:ORM之间可能存在细微的差异,这会妨碍您以真正透明的方式交换它们,并且您几乎不需要为单个项目更改ORM

第二件事,我还更喜欢将基本存储库的基本功能包装在不同的类中(Dan Bryant已经说过的装饰器模式),而不是覆盖现有的类。原因是重写常常导致必须处理基类的内部,这有时会变得有点混乱

从您的问题来看,“可审核存储库”的行为并不完全清楚,但如果它只是一个普通的
IRepository
(它审核在
IRepository
中实现的所有方法),那么您不需要单独的接口:

interface IRepository<T>
class Repository<T> : IRepository<T>
class AuditableRepository<T> : IRepository<T>
接口假定
类存储库:IRepository
类AuditableRepository:IRepository
除了Dan所说的,您还可以使用factory方法来创建适当的包装器:

class AuditableRepository<T> : IRepository<T>
{
     public static IRepository<T> CreateFrom(IRepository<T> baseRepo)
     { 
          // wrap base repo in an auditable repository
          // and return it
          return new AuditableRepository<T>(baseRepo);
     }
}
类AuditableRepository:IRepository
{
公共静态IRepository CreateFrom(IRepository baseRepo)
{ 
//在可审核的存储库中包装基本回购
//然后把它还给我
返回新的AuditableRepository(baseRepo);
}
}

存储库是否可审核重要吗?也就是说,您需要知道存储库是
iauditablepository
还是仅仅是
i存储库
?如果