【问题标题】:Generic Class for CRUD - Dependency Injection in C# using Repository and Unit Of Work PatternCRUD 的泛型类 - C# 中使用存储库和工作单元模式的依赖注入
【发布时间】:2019-03-26 06:06:06
【问题描述】:

尝试创建一个通用存储库类,用于使用依赖注入、工作单元和存储库模式在 C# 中实现基本的 CRUD 操作。

我对这些概念很陌生。以下是我的代码。

    public interface IUnitOfWork
    {
        IApplicationUserRepository Users { get; }

        ICompanyRepository Companies { get; }

        void Complete();
    }

  public class UnitOfWork : IUnitOfWork
    {
        private readonly ApplicationDbContext _context;
        public IApplicationUserRepository Users { get; private set; }
        public ICompanyRepository Companies { get; private set; }

        public UnitOfWork(ApplicationDbContext context)
        {
            _context = context;
            Users = new ApplicationUserRepository(context);
            Companies = new CompanyRepository(context);
        }

        public void Complete()
        {
            _context.SaveChanges();
        }
    }

 public interface IApplicationDbContext
    {
        DbSet<Company> Companies { get; set; }
        IDbSet<ApplicationUser> Users { get; set; }
        IDbSet<IdentityRole> Roles { get; set; }
    }

 public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext
    {
        public DbSet<Company> Companies { get; set; }
        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
        }

        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }
    }

public abstract class GenericRepository<T> : IGenericRepository<T>
        where T : class, new()
    {
        protected GenericRepository(ApplicationDbContext context)
        {
            _dbContext = context;
        }
        private ApplicationDbContext _dbContext;


        private static IEnumerable<T> entity;

        public IEnumerable<T> Get(bool forceRefresh = false)
        {
            if (forceRefresh || entity == null)
                entity = _dbContext.Set<T>();

            return entity;
        }

        public async Task AddAsync(T entity)
        {
            _dbContext.Set<T>().Add(entity);
            await _dbContext.SaveChangesAsync();
        }

        public async Task RemoveAsync(T entity)
        {
            _dbContext.Set<T>().Remove(entity);
            await _dbContext.SaveChangesAsync();
        }
    }

在上面的代码中,我想传递 IApplicationDBContext 而不是 ApplicationDBContext 以消除紧密耦合,但是当我使用 IApplicationDbContext 时,对 Set 和 SaveChanges 等方法的访问将丢失。如何在不丢失这些方法的情况下删除上述依赖项。我想通过构造函数从我的子类存储库中传递实际上下文。

【问题讨论】:

  • 工作单元模式不会替换存储库(或者在您的情况下是通用存储库,它在控制器和存储库之间添加了另一层抽象,您可以查看详细示例here
  • 用我所有的类和接口更新了代码,我在 UnitOfWork 中有一个上下文,并且想在整个项目中使用相同的上下文,不想在我的泛型类中创建一个新的上下文。
  • 在我看来,你不会通过注入 IApplicationDbContext... 再次实现任何目标,这是我的观点,但我认为应该使用一个只有 1 个实现的接口,这是有充分理由的...在这种情况下,我看不到通过注入接口为您的代码添加任何价值...如果是我,我只会注入ApplicationDbContext...这样您的代码更小更容易了解。
  • 如果要制作接口,请参阅this question...

标签: c# generics dependency-injection repository-pattern unit-of-work


【解决方案1】:

我认为,这应该做,你想要什么。如果将缺少的方法添加到接口,则基类 (DbContext) 已经实现了它。所以不需要再实现了。

public interface IApplicationDbContext<T> where T: class
{
    //Identity Management
    IDbSet<ApplicationUser> Users { get; set; }
    IDbSet<IdentityRole> Roles { get; set; }

    //Datamanagement
    DbSet<T> DataSet { get; set; } //the Dataset of T

    DbSet<U> Set<U>() where T: class; //get other DataSets
    int SaveChanges(); //save the changes
}

然后将 ApplicationDbContext 设为 Generic 并将其交给您想要访问的类型。如果您只想将它​​与 GenericRepository 一起使用,那么您可能不需要接口和类上的泛型。因为那时您只需使用已经通用的 Set()。

public class ApplicationDbContext<T> : IdentityDbContext<ApplicationUser>, IApplicationDbContext<T>
{
    public DbSet<T> DataSet{ get; set; }
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    public static ApplicationDbContext Create<T>()
    {
        return new ApplicationDbContext<T>();
    }
}

现在,上下文是通用的并且接口具有方法,您可以在存储库中使用接口。

public abstract class GenericRepository<T> : IGenericRepository<T> where T : class, new()
{
    protected GenericRepository(IApplicationDbContext<T> context)
    {
        _dbContext = context;
    }
    private TApplicationDbContext<T> _dbContext;


    private static IEnumerable<T> entity;

    public IEnumerable<T> Get(bool forceRefresh = false)
    {
        if (forceRefresh || entity == null)
            entity = _dbContext.Set<T>();

        return entity;
    }

    public async Task AddAsync(T entity)
    {
        _dbContext.Set<T>().Add(entity);
        await _dbContext.SaveChangesAsync();
    }

    public async Task RemoveAsync(T entity)
    {
        _dbContext.Set<T>().Remove(entity);
        await _dbContext.SaveChangesAsync();
    }
}

如果您不使用“默认数据集”而仅将其与存储库一起使用,则可以省略接口和上下文上的泛型。

public interface IApplicationDbContext
{
    //Identity Management
    IDbSet<ApplicationUser> Users { get; set; }
    IDbSet<IdentityRole> Roles { get; set; }

    DbSet<U> Set<U>() where T: class; //get DataSets
    int SaveChanges(); //save the changes
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}

public abstract class GenericRepository<T> : IGenericRepository<T> where T : class, new()
{

    protected GenericRepository(IApplicationDbContext context)
    {
        _dbContext = context;
    }
    private IApplicationDbContext _dbContext;


    private static IEnumerable<T> entity;

    public IEnumerable<T> Get(bool forceRefresh = false)
    {
        if (forceRefresh || entity == null)
            entity = _dbContext.Set<T>();

        return entity;
    }

    public async Task AddAsync(T entity)
    {
        _dbContext.Set<T>().Add(entity);
        await _dbContext.SaveChangesAsync();
    }

    public async Task RemoveAsync(T entity)
    {
        _dbContext.Set<T>().Remove(entity);
        await _dbContext.SaveChangesAsync();
    }
}

当然,如果你真的喜欢通用的接口和上下文,你可以使用 Repository 中的 DataSet 属性而不是 .Set()。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-10
    • 2014-10-28
    • 2023-03-23
    • 2021-11-10
    相关资源
    最近更新 更多