简体   繁体   中英

Generic Class for CRUD - Dependency Injection in C# using Repository and Unit Of Work Pattern

Trying to create a Generic Repository Class for implementing basic CRUD operations in C# using dependency injection, unit of work and repository patterns.

I am very new to these concepts. Following is my code.

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

In the above code I would like to pass IApplicationDBContext instead of ApplicationDBContext to remove tight coupling, but when i use IApplicationDbContext, access to methods like Set and SaveChanges is lost. How do I remove the above dependency without loosing these methods. I would like to pass the actual context from my child class repositories through constructor.

I think, this should do, what you want. If you add the missing methods to the Interface, the base class (DbContext) has it already implemented. So no need to implement it again.

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
}

Then make the ApplicationDbContext Generic and hand it the Type, you want to access there. I fyou only want to use it with the GenericRepository, then you might not need the Generics on the Interface and the Class. Because then you just use the already generic Set<U>().

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

Now, that the context is generic and the interface has the methods, you can use the Interface in the Repository.

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

If you don't use the "default dataset" and only use it with the repository, you can ommit the Generics on the interface and the context.

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

And of course, if you really like the generic Interface and Context, you can use the DataSet Property in the Repository instead of .Set<T>().

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM