创建通用资源库与为每个对象创建特定资源库的优势是什么?

 2023-02-17    426  

问题描述

我们正在开发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
  • 产品repository: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或其他)将完全包含在存储库实现中,但是,无论是实现该服务的人才需要知道要调用哪个存储库函数.

我猜我没有看到在服务类中写入所有表达式语法并传递给存储库的优势.这不是这个易于误扫的LINQ代码在许多情况下重复吗?

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

InvoiceRepository.GetSingleInvoice(DateTime invoiceDate, int accountId)

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

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

我看到的唯一缺点是使用具体方法的唯一缺点是我们最终可以获得许多Get *函数的排列,但这仍然似乎是将表达式逻辑推入服务类中.

我错过了什么?

推荐答案

这是一个像存储库模式本身一样旧的问题.最近引入LINQ的IQueryable,统一的查询表示,引起了大量关于这个主题的讨论.

我更喜欢自己的特定存储库,在很难建立通用存储库框架之后.无论我尝试了什么聪明的机制,我总是在同一问题上结束:存储库是正在建模的域的一部分,并且该域不是通用的.不是每个实体都可以删除,而不是可以添加每个实体,而不是每个实体都有存储库.查询疯狂地变化;存储库API作为实体本身唯一.

图案我经常使用是具有特定的存储库接口,而是实现实现的基类.例如,使用LINQ到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是一个整个其他蠕虫的蠕虫 – 在该主题上有许多意见是腹部按钮.

其他推荐答案

我实际上与布莱恩的帖子略微同意.我认为他是对的,最终一切都是非常独特的.但与此同时,大多数都是在你设计时出来的,我发现在开发我的模型时得到一个通用的存储库并使用它,我可以非常快速地提升,然后重构更大的特点,因为我找到了更大的特点需要这样做.

所以,在这样的情况下,我经常创建一个具有完整的CRUD堆栈的通用iRepository,并且让我快速玩API并让人们播放UI并进行集成和用户验收测试.在平行下.然后,正如我发现我需要在repo等上需要特定的查询,我开始替换特定的依赖关系,如果需要,从那里开始.一个底层魔术.很容易创建和使用(并且可能挂钩内存中的DB或静态对象或嘲笑对象或其他任何).

所说,我最近开始做的是打破行为.因此,如果您对IdataFetcher,IdataUpdater,IdataInterter和IdatadeLeter(例如)进行接口,可以混合和匹配以通过界面定义您的要求,然后具有照顾部分或全部的实现,我可以仍然注射了所有的实施方式,在我构建应用程序时使用.

paul

其他推荐答案

我更喜欢使用可覆盖方法签名的通用存储库(或通用存储库列表以指定确切行为的列表).

以上所述是小编给大家介绍的创建通用资源库与为每个对象创建特定资源库的优势是什么?,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/34228.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。