如何构建通用存储库

问题描述 投票:0回答:6

我正在使用 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
6个回答
6
投票

来自另一个线程

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

4
投票

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

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 */ }
}

3
投票

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

为每个对象创建通用存储库与特定存储库相比有何优势?

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

编辑:我应该指出,通用存储库的功能与特定存储库的功能非常不同。存储库旨在封装实体查询背后的数据访问机制,包括所有查询逻辑。通用存储库封装了创建查询的能力,但它不封装有关实体的任何特定查询。 重点是不要让存储库使用者负责编写自己的查询。通用存储库与 ORM 处于同一抽象级别;特定存储库的级别高于该级别。


2
投票
这是通用存储库的另一个示例


2
投票
Asp.net MVC 2 实体框架通用存储库方法。如何更新特定列

”的回答 - 它应该让您很好地了解该怎么做。 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 } }



0
投票
在此输入图片描述

我在我的项目中实现了通用存储库模式。我的文件夹结构如下所示:

摘要文件夹:

包含 IReadRepository 和 IWriteRepository 等通用接口,以及特定于模型的接口(例如 ICategoryRepository、ITutorialRepository 等),如果需要,我可以在其中定义特定于模型的方法。 混凝土文件夹:

包含通用存储库实现,例如 ReadRepository 和 WriteRepository。 此外,我为每个模型创建特定的存储库(例如,CategoryRepository、TutorialRepository),它们继承通用存储库,但也允许我添加特定于模型的方法。 我的方法: 通用实施: ReadRepository 和 WriteRepository 类处理所有模型的基本 CRUD 操作。 特定于模型的存储库: 如果模型需要特定的方法或逻辑,我会将它们添加到相应的存储库(例如 CategoryRepository)中。

这是我的界面

public interface IReadRepository<T> : IRepository<T> where T : BaseEntity, new() { Task<IEnumerable<T>> GetAllAsync(); Task<T?> GetByIdAsync(int id, bool isTracking, params string[] includes); Task<T?> GetSingleByConditionAsync(Expression<Func<T, bool>> condition); IQueryable<T> GetAllByConditionAsync(Expression<Func<T, bool>> condition); Task CreateAsync(T entity); void Update(T entity); void Delete(T entity); void DeleteRange(params T[] entities); Task<int> SaveChangeAsync();

}

和这个存储库

public class WriteRepository<T> : IWriteRepository<T> where T : BaseEntity, new() { private readonly AppDbContext _context; public WriteRepository(AppDbContext context) { _context = context; } public DbSet<T> Table => _context.Set<T>(); public async Task CreateAsync(T entity) { await Table.AddAsync(entity); } public void Delete(T entity) { Table.Remove(entity); } public void DeleteRange(params T[] entities) { Table.RemoveRange(entities); } public async Task<int> SaveChangeAsync() { int rows = await _context.SaveChangesAsync(); return rows; } public void Update(T entity) { Table.Update(entity); } public async Task<T?> GetByIdAsync(int id, bool isTracking, params string[] includes) { IQueryable<T> query = Table.AsQueryable(); if (!isTracking) { query = query.AsNoTracking(); } if (includes.Length > 0) { foreach (string include in includes) { query = query.Include(include); } } T? entity = await query.SingleOrDefaultAsync(e => e.Id == id); return entity; } public async Task<T?> GetSingleByConditionAsync(Expression<Func<T, bool>> condition) { IQueryable<T> query = Table.AsQueryable(); T? entity = await query.SingleOrDefaultAsync(condition); return entity; } public IQueryable<T> GetAllByConditionAsync(Expression<Func<T, bool>> condition) { IQueryable<T> query = Table.AsQueryable(); query = query.Where(condition); return query; } public async Task<IEnumerable<T>> GetAllAsync() { return await _context.Set<T>().ToListAsync(); }

}

© www.soinside.com 2019 - 2024. All rights reserved.