且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-02-13 15:27:35

这是一个与存储库模式本身一样古老的问题.最近 LINQ 的 IQueryable(查询的统一表示)的引入引起了很多关于这个话题的讨论.

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.

在努力构建通用存储库框架之后,我自己更喜欢特定的存储库.无论我尝试过什么聪明的机制,我总是遇到同样的问题:存储库是被建模域的一部分,而该域不是通用的.不是每个实体都可以删除,不是每个实体都可以添加,不是每个实体都有一个存储库.查询千差万别;存储库 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.