我正在使用 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);
}
}
有一种方法可以创建一种我可以在所有课程中使用的通用存储库吗?
如果可能的话,如果我需要为特定类创建特定方法,我该怎么办?
来自另一个线程:
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);
}
}
您应该创建一个通用存储库,您可以在一般情况下使用它,如果特定类需要任何额外的方法,请通过使用继承来添加它。用你的例子:
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 */ }
}
这是我对类似问题的回答(截至目前有28票):
这个想法是通用化实现,而不是接口。创建一个面向内的通用存储库基类,而不是面向外的通用存储库接口,您可以使用它来轻松实现特定于实体的接口。
编辑:我应该指出,通用存储库的功能与特定存储库的功能非常不同。存储库旨在封装实体查询背后的数据访问机制,包括所有查询逻辑。通用存储库封装了创建查询的能力,但它不封装有关实体的任何特定查询。 重点是不要让存储库使用者负责编写自己的查询。通用存储库与 ORM 处于同一抽象级别;特定存储库的级别高于该级别。
”的回答 - 它应该让您很好地了解该怎么做。 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
}
}
我在我的项目中实现了通用存储库模式。我的文件夹结构如下所示:
摘要文件夹:
包含 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();
}
}