在创建每个对象的通用信息库与库特定的优势在哪里?(Advantage of creating a g

2019-06-18 01:49发布

我们正在开发一个ASP.NET MVC应用程序,并正在建立资料库/服务类。 我不知道是否有创造的所有库实现一个通用的接口IRepository任何重大的优势,对每个存储库有它自己独特的界面和设置的方法。

例如:通用IRepository接口可能看起来像(取自这个答案 ):

public interface IRepository : IDisposable
{
    T[] GetAll<T>();
    T[] GetAll<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter, List<Expression<Func<T, object>>> subSelectors);
    void Delete<T>(T entity);
    void Add<T>(T entity);
    int SaveChanges();
    DbTransaction BeginTransaction();
}

每个存储库将实现这个接口,例如:

  • CustomerRepository:IRepository
  • ProductRepository:IRepository
  • 等等

我们已经遵循以前项目的替代将是:

public interface IInvoiceRepository : IDisposable
{
    EntityCollection<InvoiceEntity> GetAllInvoices(int accountId);
    EntityCollection<InvoiceEntity> GetAllInvoices(DateTime theDate);
    InvoiceEntity GetSingleInvoice(int id, bool doFetchRelated);
    InvoiceEntity GetSingleInvoice(DateTime invoiceDate, int accountId); //unique
    InvoiceEntity CreateInvoice();
    InvoiceLineEntity CreateInvoiceLine();
    void SaveChanges(InvoiceEntity); //handles inserts or updates
    void DeleteInvoice(InvoiceEntity);
    void DeleteInvoiceLine(InvoiceLineEntity);
}

在第二种情况下,表达式(LINQ或其他方式)将被完全包含在资源库实现,不管是谁实现服务只需知道要调用的库函数。

我想我没有看到在服务类编写所有的表达式语法,并传递到存储库的优势。 这是不是意味着易于messup LINQ代码在很多情况下被复制?

例如,在我们的旧发票系统,我们称之为

InvoiceRepository.GetSingleInvoice(DateTime invoiceDate, int accountId)

从几个不同的服务(客户,发票,账户等)。 这似乎比写在多个地方下面更清洁:

rep.GetSingle(x => x.AccountId = someId && x.InvoiceDate = someDate.Date);

唯一的缺点我看到使用具体做法是,我们可以用获取*函数许多排列结束了,但这似乎仍然最好推的表达逻辑成服务类。

我在想什么?

Answer 1:

这是一个问题,因为旧的存储库模式本身。 最近推出的LINQ的的IQueryable ,查询的统一表示,已经引起了很多讨论关于这个题目。

我更喜欢具体的仓库自己,在已经非常努力建立一个通用的存储库框架。 不管我试了一下聪明的机制,我总是结束了在同样的问题:一个是仓库建模域的一部分,而该域不通用。 并不是每一个实体可以被删除,可以加入不是每一个实体,并非每个实体都有一个存储库。 查询大相径庭; 库API随着实体本身独特。

我经常使用一个模式是具有特定的库接口,但是对于实现的基类。 例如,使用LINQ to SQL,你可以这样做:

public abstract class Repository<TEntity>
{
    private DataContext _dataContext;

    protected Repository(DataContext dataContext)
    {
        _dataContext = dataContext;
    }

    protected IQueryable<TEntity> Query
    {
        get { return _dataContext.GetTable<TEntity>(); }
    }

    protected void InsertOnCommit(TEntity entity)
    {
        _dataContext.GetTable<TEntity>().InsertOnCommit(entity);
    }

    protected void DeleteOnCommit(TEntity entity)
    {
        _dataContext.GetTable<TEntity>().DeleteOnCommit(entity);
    }
}

替换DataContext你的单位的工作选择。 示例实现可能是:

public interface IUserRepository
{
    User GetById(int id);

    IQueryable<User> GetLockedOutUsers();

    void Insert(User user);
}

public class UserRepository : Repository<User>, IUserRepository
{
    public UserRepository(DataContext dataContext) : base(dataContext)
    {}

    public User GetById(int id)
    {
        return Query.Where(user => user.Id == id).SingleOrDefault();
    }

    public IQueryable<User> GetLockedOutUsers()
    {
        return Query.Where(user => user.IsLockedOut);
    }

    public void Insert(User user)
    {
        InsertOnCommit(user);
    }
}

注意仓库的公共API不允许用户将被删除。 此外,揭露IQueryable是蠕虫的一个整体的其他罐头-有许多意见,有关该主题的肚脐。



Answer 2:

其实我与布莱恩的帖子稍微不同意。 我认为他是正确的,最终一切都非常独特,等等。 但在同一时间,大部分的散发出来为你设计,我发现当一个通用存储库和使用它,而发展我的模型,我可以得到一个应用程序启动速度极快,然后重构,以更大的特异性,因为我找到了需要这样做。

所以,在这样的情况下,我经常创造出了完整的CRUD栈通用IRepository,这让我很快地得到与API玩,让乡亲发挥瓦特/ UI做集成和用户验收测试并行。 然后,当我发现我需要具体问题上的回购,等等,我开始,如果需要更换这种依赖性瓦特/特定的一个,并从那里去。 一个潜在的IMPL。 很容易创建和使用(并且可能勾在内存中的分贝或静态对象或对象嘲笑或其他)。

这就是说,我已经开始做最近是分手的行为。 所以,如果你对IDataFetcher,IDataUpdater,IDataInserter和IDataDeleter(例如)做接口,你可以混合和匹配,以通过接口定义你的需求,然后有需要的部分或全部的护理实现,我可以还注入做它,所有的实现,而我正在创建的应用程序在使用。

保罗



Answer 3:

我喜欢用重写的方法签名从通用存储库导出(或通用库的列表来指定具体的行为)的特定存储库。



Answer 4:

有一个由特定的资源库包裹通用仓库。 你可以控制的公共接口,但仍然这样,有一些代码重用的优点是,来自于有一个通用的存储库。



Answer 5:

公共类UserRepository:仓库,IUserRepository

你不应该注入IUserRepository避免暴露的接口。 正如人们所说的,你可能不需要完整的CRUD栈等。



文章来源: Advantage of creating a generic repository vs. specific repository for each object?