【问题标题】:How to build a generic repository如何构建通用存储库
【发布时间】:2010-09-28 20:00:46
【问题描述】:

我正在使用 NHibernate 在 ASP.NET MVC 中开发一个 Web 应用程序。

根据我在 Google 上找到的文章和教程,我将 Repository 用于我的课程。

我有 10 个类和 10 个存储库。今天我发现我的 90% 的存储库是完全相等的,除了类。这是一个例子:

public class PromocaoRepository:IPromocaoRepository {
    private ISession Session;

    public PromocaoRepository() {
        this.Session = NHibernateSessionFactory.OpenSession();
    }

    public void Add(Promocao promocao) {
        using(ITransaction transaction = this.Session.BeginTransaction()) {
            this.Session.Save(promocao);
            transaction.Commit();
        }
    }

    public void Edit(Promocao promocao) {
        using(ITransaction transaction = this.Session.BeginTransaction()) {
            this.Session.Update(promocao);
            transaction.Commit();
        }
    }

    public void Remove(Promocao promocao) {
        using(ITransaction transaction = this.Session.BeginTransaction()) {
            this.Session.Delete(promocao);
            transaction.Commit();
        }
    }

    public Promocao GetById(int id) {
        return this.Session.Get<Promocao>(id);
    }

}

有一种方法可以做一种我可以在所有课程中使用的通用存储库吗?

如果可能,如果我需要为特定类创建特定方法,我应该怎么做?

【问题讨论】:

标签: asp.net-mvc nhibernate design-patterns oop repository


【解决方案1】:

来自another thread

public interface IRepository<T> : IQueryable<T>
{
  void Add(T entity);
  T Get(Guid id);
  void Remove(T entity);
}

public class Repository<T> : IQueryable<T>
{
  private readonly ISession session;

  public Repository(ISession session)
  {
    session = session;
  }

  public Type ElementType
  {
    get { return session.Query<T>().ElementType; }
  }

  public Expression Expression
  {
    get { return session.Query<T>().Expression; }
  }

  public IQueryProvider Provider
  {
    get { return session.Query<T>().Provider; } 
  }  

  public void Add(T entity)
  {
    session.Save(entity);
  }

  public T Get(Guid id)
  {
    return session.Get<T>(id);
  }

  IEnumerator IEnumerable.GetEnumerator()
  {
    return this.GetEnumerator();
  }

  public IEnumerator<T> GetEnumerator()
  {
    return session.Query<T>().GetEnumerator();
  }

  public void Remove(T entity)
  {
    session.Delete(entity);
  }   
}

【讨论】:

  • 从未想过让存储库继承 IQueryable。对此有何警告?
  • 它不是继承而是实现,IQueryable是一个接口。它基本上所做的只是将调用转发到已经内置 LINQ IQueryable 实现的 session.Query
  • 这个答案很有启发性!我会全部研究的。非常感谢。
【解决方案2】:

您应该创建一个通用存储库,您可以在一般情况下使用它,如果特定类需要任何额外的方法,请使用继承添加它。使用您的示例:

public class GenericRepository<TEntity> :IGenericRepository<TEntity> {
    private ISession Session;

    public GenericRepository() {
        this.Session = NHibernateSessionFactory.OpenSession();
    }

    public void Add(TEntity instance) {
        using(ITransaction transaction = this.Session.BeginTransaction()) {
            this.Session.Save(instance);
            transaction.Commit();
        }
    }

    /* other methods */ 
}

public class SpecificRepository : GenericRepository<SpecificEntity>, ISpecificRepository 
{
    public void SpecialQuery()  { /* added method implementation */ }
}

【讨论】:

  • 谢谢!我只需要将我的 ISession Session 设置为子存储库的受保护/公共。
【解决方案3】:

这是我对类似问题的回答(截至目前 28 票):

Advantage of creating a generic repository vs. specific repository for each object?

这个想法是泛化实现,而不是接口。创建一个面向内部的通用存储库基类,而不是面向外部的通用存储库接口,您可以使用它轻松实现特定于实体的接口。

编辑:我应该指出,通用存储库提供的功能与特定存储库非常不同。存储库旨在封装实体查询背后的数据访问机制,包括所有查询逻辑。通用存储库封装了创建查询的能力,但它不封装关于实体的任何特定查询。

关键是不要让存储库消费者负责编写自己的查询。通用存储库与 ORM 处于同一抽象级别;特定的存储库位于高于此的级别。

【讨论】:

    【解决方案4】:
    【解决方案5】:

    看看我对“Asp.net MVC 2 Entity Framework Generic Repository Method. how to Update a specific Collumn”问题的回答——它应该让你知道该怎么做。

    HTH, 查尔斯

    例如

    基础模型:

    public interface IDbTable
    {
        int Id { get; set; }
        DateTime DateCreated { get; set; }
        DateTime DateUpdated { get; set; }
    }
    
    public class DbTable
    {
        public int Id { get; set; }
        public DateTime DateCreated { get; set; }
        public DateTime DateUpdated { get; set; }
    }
    

    你的模型

    public class Category : DbTable
    {
        public string Name { get; set; }
    }
    

    你的仓库

    public interface IBaseRepository<T> where T : class, IDbTable
    {
        void Add<T>(T entity);
        void Edit<T>(T entity);
        void Remove<T>(T entity);
        T GetById(int id);
    }
    
    public class BaseRepository<T> : IBaseRepository<T>
    {
        private ISession Session;
    
        public BaseRepository()
        {
            this.Session = NHibernateSessionFactory.OpenSession();
        }
    
        public void Add(T entity)
        {
            entity.DateCreated = DateTime.UtcNow;
            entity.DateUpdated = DateTime.UtcNow;
    
            using(ITransaction transaction = this.Session.BeginTransaction())
            {
                this.Session.Save(entity);
                transaction.Commit();
            }
        }
    
        public void Edit(T entity)
        {
            entity.DateUpdated = DateTime.UtcNow;
    
            using(ITransaction transaction = this.Session.BeginTransaction())
            {
                this.Session.Update(entity);
                transaction.Commit();
            }
        }
    
        public void Remove(T entity)
        {
            using(ITransaction transaction = this.Session.BeginTransaction())
            {
                this.Session.Delete(entity);
                transaction.Commit();
            }
        }
    
        public T GetById(int id)
        {
            return this.Session.Get<T>(id);
        }
    }
    

    哦,别忘了具体的实现

    public interface ICategoryRepository : IBaseRepository<Category>
    {
        Category GetCategoryByName(string categoryName);
    }
    
    public CategoryRepository : BaseRepository<Category>
    {
        public Category GetCategoryByName(string categoryName)
        {
            //blah
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-15
      • 2017-04-27
      • 1970-01-01
      • 2014-11-26
      • 1970-01-01
      相关资源
      最近更新 更多