Шаблон репозитория вопросов - PullRequest
0 голосов
/ 07 октября 2019

В последнее время я реализовал шаблон репозитория и единицу работы (используя общий репозиторий), потому что это помогает модульному тестированию. Есть много учебных пособий, которые конфликтуют друг с другом.

У меня есть несколько вопросов, связанных с моим кодом ниже:

  • В настоящее время я добавляю IUnitOfWork/UnitOfWork в качестве службы области вStartup.cs. Я не совсем уверен, должен ли это быть один экземпляр (синглтон) или новый экземпляр (в области видимости), или даже временный.
  • Я пропустил что-то еще, кроме реализации IDisposable в UnitOfWork?
  • Что-то еще не так с моим шаблоном репозитория / реализацией UnitOfWork?

IUnitOfWork.cs

using System.Threading.Tasks;

namespace SaveBees.Repositories
{
    public interface IUnitOfWork
    {
        IUserRepository Users { get; }
        IRoleRepository Roles { get; }

        Task<int> SaveAsync();
    }
}

UnitOfWork.cs

using System;
using System.Threading.Tasks;

namespace SaveBees.Repositories
{
    public class UnitOfWork : IUnitOfWork, IDisposable
    {
        private readonly SaveBeesContext _context;

        public UnitOfWork(SaveBeesContext context)
        {
            _context = context;
        }

        private IRoleRepository _roleRepository;

        public IRoleRepository Roles
        {
            get
            {
                if (_roleRepository == null)
                {
                    _roleRepository = new RoleRepository(_context);
                }

                return _roleRepository;
            }
        }

        private IUserRepository _userRepository;

        public IUserRepository Users
        {
            get
            {
                if (_userRepository == null)
                {
                    _userRepository = new UserRepository(_context);
                }

                return _userRepository;
            }
        }

        public async Task<int> SaveAsync()
        {
            return await _context.SaveChangesAsync();
        }

        private bool _disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _context.Dispose();
                }
            }
            _disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}

IGeneralRepository.cs

using SaveBees.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace SaveBees.Repositories
{
    public interface IGenericRepository<TEntity> where TEntity : class, IEntity
    {
        Task<List<TEntity>> GetAllAsync(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, Func<IQueryable<TEntity>, IQueryable<TEntity>> includes = null);
        Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, bool>> filter, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, Func<IQueryable<TEntity>, IQueryable<TEntity>> includes = null);
        Task<TEntity> GetByIdAsync(int id, Func<IQueryable<TEntity>, IQueryable<TEntity>> includes = null);
        Task<TEntity> SingleOrDefaultAsync(Expression<Func<TEntity, bool>> filter, Func<IQueryable<TEntity>, IQueryable<TEntity>> includes = null);
        Task AddAsync(TEntity entity);
        void Update(TEntity entity);
        void Remove(TEntity entity);
    }
}

GeneralRepository.cs

using Microsoft.EntityFrameworkCore;
using SaveBees.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace SaveBees.Repositories
{
    public abstract class GenericRepository<TEntity, TContext> : IGenericRepository<TEntity>
        where TEntity : class, IEntity
        where TContext : DbContext
    {
        private readonly TContext _context;

        public GenericRepository(TContext context)
        {
            _context = context;
        }

        public async Task<List<TEntity>> GetAllAsync(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, Func<IQueryable<TEntity>, IQueryable<TEntity>> includes = null)
        {
            IQueryable<TEntity> query = _context.Set<TEntity>();

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

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

            return await query.ToListAsync();
        }

        public async Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, bool>> filter, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, Func<IQueryable<TEntity>, IQueryable<TEntity>> includes = null)
        {
            IQueryable<TEntity> query = _context.Set<TEntity>();

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

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

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

            return await query.ToListAsync();
        }

        public async Task<TEntity> GetByIdAsync(int id, Func<IQueryable<TEntity>, IQueryable<TEntity>> includes = null)
        {
            IQueryable<TEntity> query = _context.Set<TEntity>();

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

            return await query.SingleOrDefaultAsync(x => x.Id == id);
        }

        public async Task<TEntity> SingleOrDefaultAsync(Expression<Func<TEntity, bool>> filter, Func<IQueryable<TEntity>, IQueryable<TEntity>> includes = null)
        {
            IQueryable<TEntity> query = _context.Set<TEntity>();

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

            return await query.SingleOrDefaultAsync(filter);
        }

        public async Task AddAsync(TEntity entity)
        {
            await _context.Set<TEntity>().AddAsync(entity);
        }

        public void Update(TEntity entity)
        {
            _context.Set<TEntity>().Update(entity);
        }

        public void Remove(TEntity entity)
        {
            _context.Remove(entity);
        }
    }
}

IUserRepository.cs

using SaveBees.Models;
using System.Threading.Tasks;

namespace SaveBees.Repositories
{
    public interface IUserRepository : IGenericRepository<User>
    {
        Task<User> GetByEmailAsync(string email);
    }
}

UserRepository.cs

using Microsoft.EntityFrameworkCore;
using SaveBees.Models;
using System.Threading.Tasks;

namespace SaveBees.Repositories
{
    public class UserRepository : GenericRepository<User, SaveBeesContext>, IUserRepository
    {
        public UserRepository(SaveBeesContext context) : base(context)
        {
        }

        public async Task<User> GetByEmailAsync(string email)
            => await SingleOrDefaultAsync(e => e.Email == email,
                e => e.Include(u => u.UserRoles)
                    .ThenInclude(ur => ur.Role));
    }
}

IEntity.cs

namespace SaveBees.Data
{
    public interface IEntity
    {
        public int Id { get; set; }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...