首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为每个对象创建通用存储库与特定存储库的优势?

为每个对象创建通用存储库与特定存储库的优势?
EN

Stack Overflow用户
提问于 2009-08-05 00:18:19
回答 5查看 33.6K关注 0票数 134

我们正在开发一个ASP.NET MVC应用程序,现在正在构建存储库/服务类。我想知道,创建一个所有存储库都实现的通用IRepository接口与每个存储库都有自己独特的接口和方法集相比,有没有什么主要优势。

例如:一个通用的IRepository接口可能类似于(取自this answer):

代码语言:javascript
复制
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
  • etc.

我们在以前的项目中遵循的备选方案是:

代码语言:javascript
复制
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或其他)将完全包含在存储库实现中,任何实现服务的人只需要知道要调用哪个存储库函数。

我想我看不到在服务类中编写所有表达式语法并将其传递给存储库的好处。这不是意味着在许多情况下,易于使用的LINQ代码正在被复制吗?

例如,在我们的旧发票系统中,我们调用

代码语言:javascript
复制
InvoiceRepository.GetSingleInvoice(DateTime invoiceDate, int accountId)

来自一些不同的服务(客户、发票、账户等)。这似乎比在多个地方编写以下代码要干净得多:

代码语言:javascript
复制
rep.GetSingle(x => x.AccountId = someId && x.InvoiceDate = someDate.Date);

我看到使用特定方法的唯一缺点是,我们最终可能会得到许多Get*函数的排列,但这似乎仍然比将表达式逻辑推入服务类更可取。

我遗漏了什么?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2009-08-05 06:12:56

这是一个与Repository模式本身一样古老的问题。最近LINQ的IQueryable的引入,一个查询的统一表示,已经引起了关于这个话题的很多讨论。

我自己更喜欢特定的存储库,因为我非常努力地构建了一个通用存储库框架。无论我尝试了什么聪明的机制,我总是遇到相同的问题:存储库是正在建模的域的一部分,而该域不是通用的。不是每个实体都可以删除,也不是每个实体都可以添加,也不是每个实体都有存储库。查询变化很大;存储库API变得和实体本身一样独特。

我经常使用的一种模式是具有特定的存储库接口,但有一个用于实现的基类。例如,使用LINQ to SQL,您可以执行以下操作:

代码语言:javascript
复制
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替换为您选择的工作单元。一个示例实现可能是:

代码语言:javascript
复制
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是一个完全不同的问题--关于这个话题,众说纷云。

票数 176
EN

Stack Overflow用户

发布于 2010-03-20 21:56:07

实际上,我有点不同意布莱恩的帖子。我认为他是对的,归根结底,一切都是非常独特的。但与此同时,大部分都是你设计出来的,我发现建立一个通用存储库并在开发我的模型时使用它,我可以非常快地建立一个应用程序,然后在我发现需要这样做的时候重构到更具体的地方。

因此,在这样的情况下,我经常创建一个具有完整CRUD堆栈的通用IRepository,这让我可以快速地开始使用它,让人们使用UI并并行地进行集成和用户验收测试。然后,当我发现我需要关于repo的特定查询时,如果需要,我开始用特定的依赖替换该依赖,并从那里开始。一个潜在的实施。易于创建和使用(并且可能挂钩到内存中的db或静态对象或模拟对象或其他任何对象)。

也就是说,我最近开始做的是打破这种行为。因此,如果您为IDataFetcher、IDataUpdater、IDataInserter和IDataDeleter (例如)创建接口,您可以通过接口混合匹配来定义您的需求,然后让实现部分或全部满足这些需求,并且我仍然可以在构建应用程序时注入do -it- all实现来使用。

保罗

票数 27
EN

Stack Overflow用户

发布于 2009-08-05 07:21:48

我更喜欢从具有可重写方法签名的泛型存储库(或泛型存储库列表来指定确切的行为)派生的特定存储库。

票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1230571

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档