创建为每个对象的通用信息库与库特定的优势在哪里? [英] Advantage of creating a generic repository vs. specific repository for each object?

查看:102
本文介绍了创建为每个对象的通用信息库与库特定的优势在哪里?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We are developing an ASP.NET MVC application, and are now building the repository/service classes. I'm wondering if there are any major advantages to creating a generic IRepository interface that all repositories implement, vs. each Repository having its own unique interface and set of methods.

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

For example: a generic IRepository interface might look like (taken from this answer):

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();
}

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

Each Repository would implement this interface, for example:


  • CustomerRepository:IRepository

  • ProductRepository:IRepository


这是我们一直遵循之前的项目交替将是:

The alternate that we've followed in prior projects would be:

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);
}

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

In the second case, the expressions (LINQ or otherwise) would be entirely contained in the Repository implementation, whoever is implementing the service just needs to know which repository function to call.

我想我没有看到在服务类编写所有的前pression语法和传递到存储库的优势。这是不是意味着容易messup LINQ code在许多情况下被复制?

I guess I don't see the advantage of writing all the expression syntax in the service class and passing to the repository. Wouldn't this mean easy-to-messup LINQ code is being duplicated in many cases?

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

For example, in our old invoicing system, we call

InvoiceRepository.GetSingleInvoice(DateTime invoiceDate, int accountId)

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

from a few different services (Customer, Invoice, Account, etc). That seems much cleaner than writing the following in multiple places:

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

唯一的缺点我看到使用的具体做法是,我们可以用获取*函数多少排列结束了,但这似乎仍preferable来推前pression逻辑成服务类。

The only disadvantage I see to using the specific approach is that we could end up with many permutations of Get* functions, but this still seems preferable to pushing the expression logic up into the Service classes.

我是什么失踪?

推荐答案

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

This is an issue as old as the Repository pattern itself. The recent introduction of LINQ's IQueryable, a uniform representation of a query, has caused a lot of discussion about this very topic.

我preFER特定的仓库自己,在已经很努力打造一个通用存储库框架。不管我试了一下聪明的机制,我总是结束了在同样的问题:一个库是被模拟域的一部分,而该域不通用的。不是每一个实体可以被删除,可以加入不是每个实体,而不是每一个实体具有存储库。查询大相径庭;库API变得实体本身独特。

I prefer specific repositories myself, after having worked very hard to build a generic repository framework. No matter what clever mechanism I tried, I always ended up at the same problem: a repository is a part of the domain being modeled, and that domain is not generic. Not every entity can be deleted, not every entity can be added, not every entity has a repository. Queries vary wildly; the repository API becomes as unique as the entity itself.

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

A pattern I often use is to have specific repository interfaces, but a base class for the implementations. For example, using LINQ to SQL, you could do:

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 与你单位的工作选择。示例实现可能是:

Replace DataContext with your unit-of-work of choice. An example implementation might be:

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 是蠕虫病毒的完全是另外一个可以 - 有许多意见,关于这一主题的肚脐。

Notice the public API of the repository does not allow users to be deleted. Also, exposing IQueryable is a whole other can of worms - there are as many opinions as belly buttons on that topic.

这篇关于创建为每个对象的通用信息库与库特定的优势在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆