【问题标题】:Generic repository implementation with base repository as abstract class以基础存储库作为抽象类的通用存储库实现
【发布时间】:2020-08-01 13:48:00
【问题描述】:

网络核心项目。我正在尝试实现通用存储库模式。我有抽象的基础存储库。所以我正在覆盖基础存储库并创建我的其他存储库。实现如下所示。

BaseRepository.cs

 public abstract class BaseRepository<T>: IBaseRepository<T>
        where T : class
    {
       private readonly DbContext dbContext;
       private readonly DbSet<T> dbSet;
       public BaseRepository(DbContext dbContext)
        {
            this.dbContext = dbContext;
            this.dbSet = dbContext?.Set<T>();
        }
      public async Task<IEnumerable<T>> GetAsync(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, params Expression<Func<T, object>>[] includes)
        {
            IQueryable<T> query = this.dbSet;
            foreach (Expression<Func<T, object>> include in includes)
            {
                query = query.Include(include);
            }

            if (filter != null)
            {
                query = query.Where(filter);
            }

            if (orderBy != null)
            {
                query = orderBy(query);
            }

            return await query.ToListAsync().ConfigureAwait(false);
        }
     }
   }

Repository.cs

public class Repository<T> : BaseRepository<T>, IRepository<T>
        where T : class
    {
     private readonly DbContext dbContext;
     private readonly DbSet<T> dbSet;
     public Repository(DbContext context) : base(context)
        {
        }
     public async Task<IEnumerable<T>> GetAsync(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, params Expression<Func<T, object>>[] includes)
        {
            IQueryable<T> query = this.dbSet;
            foreach (Expression<Func<T, object>> include in includes)
            {
                query = query.Include(include);
            }

            if (filter != null)
            {
                query = query.Where(filter);
            }

            if (orderBy != null)
            {
                query = orderBy(query);
            }

            return await query.ToListAsync().ConfigureAwait(false);
        }
     }
   }

UnitOfWork.cs

public class UnitOfWork<TContext> : IUnitOfWork<TContext>
        where TContext : DbContext, IDisposable
    {
     private readonly MyContext context;
     private Dictionary<(Type type, string name), object> _repositories;
     public UnitOfWork(MyContext myContext)
        {
            if (this.context == null)
            {
                this.context = myContext;
            }
        }
     public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
        {
            return (IRepository<TEntity>)GetOrAddRepository(typeof(TEntity), new Repository<TEntity>(Context));
        }
      public async Task<int> CompleteAsync()
        {
            try
            {
                return await this.context.SaveChangesAsync().ConfigureAwait(false);
            }
            catch (DbUpdateConcurrencyException ex)
            {
                ex.Entries.Single().Reload();
                return await this.context.SaveChangesAsync().ConfigureAwait(false);
            }
        }
      internal object GetOrAddRepository(Type type, object repo)
        {
            _repositories ??= new Dictionary<(Type type, string Name), object>();

            if (_repositories.TryGetValue((type, repo.GetType().FullName), out var repository)) return repository;
            _repositories.Add((type, repo.GetType().FullName), repo);
            return repo;
        }
    }
  }

然后在我注册时的 startup.cs 文件中

services.AddDbContext<MyContext>(options =>
       options.UseSqlServer(this.Configuration["AzureSQLConnectionString"]));
        services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
        services.AddScoped<IUnitOfWork, UnitOfWork>();

UnitofWork 使用泛型类型“UnitofWork”会引发错误,需要 1 种类型的参数。然后我添加了services.AddScoped&lt;IUnitOfWork, UnitOfWork&lt;MyContext&gt;&gt;()。现在它在 Repository.cs 的 GetAsync 方法中抛出错误。错误是 Parameter: source is required, 它不能为空。然后我发现了

IQueryable 查询 = this.dbSet;

查询为空。所以我的理解是我在建立与数据库的连接时遇到了一些问题。有人可以帮助我在这里到底做错了什么吗?任何帮助将不胜感激。谢谢

【问题讨论】:

  • 根据您的代码,您没有覆盖任何内容。基类和派生类的实现是相同的,但即使它不同,您也不会将基方法标记为 virtual 以便它可以被覆盖。我只是指出这一点,并不是你要问的。
  • 是的,谢谢你提醒我。我现在把它变成虚拟的。但是我遇到了 dbcontext 的问题。我该如何解决这个问题?
  • 尝试在基类中保护上下文和数据库集,并去掉派生类中的私有字段。您只是在基类中进行初始化。如果 GetAsync 的代码没有改变,您不需要重新实现它,但请阅读我之前的评论并标记为虚拟,以防某些 repo 需要覆盖它。
  • 在 Repository.cs 中,我将 Dbcontext 设为空。这是问题,但我真的很挣扎我该如何解决这个问题?
  • 我在之前的评论中解释了为什么会发生这种情况。您的 repo 类正在使用其从未初始化的私有上下文。它没有从基类中获取它。

标签: c# generics repository-pattern ef-core-3.1


【解决方案1】:

如下更改这些类:

public abstract class BaseRepository<T>: IBaseRepository<T>
        where T : class
    {
       protected readonly DbContext dbContext;
       protected readonly DbSet<T> dbSet;

       public BaseRepository(DbContext dbContext)
        {
            this.dbContext = dbContext;
            this.dbSet = dbContext?.Set<T>();
        }
      public virtual async Task<IEnumerable<T>> GetAsync(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, params Expression<Func<T, object>>[] includes)
        {
            IQueryable<T> query = this.dbSet;
            foreach (Expression<Func<T, object>> include in includes)
            {
                query = query.Include(include);
            }

            if (filter != null)
            {
                query = query.Where(filter);
            }

            if (orderBy != null)
            {
                query = orderBy(query);
            }

            return await query.ToListAsync().ConfigureAwait(false);
        }
     }

public class Repository<T> : BaseRepository<T>, IRepository<T>
        where T : class
    {
     
        public Repository(DbContext context) : base(context)
        {
        }

        //override GetAsync if different than base. In your case it is not.
     }

【讨论】:

  • 您好,感谢您的回答。这个想法是将应用程序与不同的存储库集成。目前我只有baserepository 和repository。将来我将拥有更多的存储库,例如存储库 1,2 等。这就是整个想法,我正在努力实现它。那么我走的是正确的道路吗?
  • 因此,对于上述要求,我假设我应该在基础存储库中将方法设为抽象,对吧?因为我将在存储库中实现。我的理解正确吗?
  • 关于您的第一个问题,您可能想阅读this posting 之类的内容。至于抽象方法,如果你不能提供默认实现,则将其抽象,否则将其设为虚拟并添加代码,如示例中所示。
猜你喜欢
  • 2019-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
  • 2014-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多