Единица работы и шаблон репозитория при внедрении конструктора контроллера MVC с использованием Unity, не внося никаких изменений в базу данных - PullRequest
0 голосов
/ 18 октября 2018

1.) Я создаю новое MVC-приложение с 3-уровневой архитектурой проекта, имеющее:

  1. Общий проект с сущностями
  2. Интерфейсы для хранения бизнес-услуг и логические классы и
  3. Хранилища данных, интерфейсы, DbContext и UnitOfWork классы.Я использую Unity Config для регистрации зависимостей DbContext и UnitOfWork.

2.) Я создал репозиторий для каждой таблицы и один общий репозиторий, который выполняет основные операции CRUD.

Пример сущности, находящейся в общем проекте:

public class MenuSecd
{
    [Key, Column(Order = 0)]
    public string prg_module { get; set; }
    [Key, Column(Order = 1)]
    public int prg_numb { get; set; }
    [Key, Column(Order = 2)]
    public string menu_level { get; set; }
}

Мой универсальный интерфейс логики сущности, находящийся в бизнес-проекте:

public interface IEntityLogic<T> : ILogic where T : class
{
    void Create(T entity);
    void Delete(T entity);
    IEnumerable<T> GetAll();
    void Update(T entity);
}

Класс логики сущности:

public abstract class EntityLogic<T> : IEntityLogic<T> where T : class
{
    IUnitOfWork _unitOfWork;
    IGenericRepository<T> _repository;

    public EntityLogic(IUnitOfWork unitOfWork, IGenericRepository<T> repository)
    {
        _unitOfWork = unitOfWork;
        _repository = repository;
    }

    public virtual void Create(T entity)
    {
        if(entity == null)
        {
            throw new ArgumentNullException(nameof(entity));
        }

        _repository.Add(entity);
        _unitOfWork.Commit();
    }
}

Пример класса бизнес-логики для сущности, определенной в общем проекте:

public class MenuSecdLogic : EntityLogic<MenuSecd>, IMenuSecdLogic
{
    IUnitOfWork _unitOfWork;
    IMenuSecdRepository _repository;
    public MenuSecdLogic(IUnitOfWork unitOfWork, IMenuSecdRepository repository) : base(unitOfWork, repository)
    {
        _unitOfWork = unitOfWork;
        _repository = repository;
    }

    public List<MenuSecd> GetItems(string usrgrp_id)
    {
        return _repository.GetItems(usrgrp_id);
    }
}

Мой общий репозиторий в проекте данных выглядит следующим образом:

public abstract class GenericRepository<T> : IGenericRepository<T> where T : class
{
    protected DbContext _entities;
    protected readonly IDbSet<T> _dbset;
    public GenericRepository(DbContext context)
    {
        _entities = context;
        _dbset = context.Set<T>();
    }
    public virtual T Add(T entity)
    {
        return _dbset.Add(entity);
    }

    public virtual T Delete(T entity)
    {
        return _dbset.Remove(entity);
    }

    public virtual void Edit(T entity)
    {
        _entities.Entry(entity).State = EntityState.Modified;
    }
}

Интерфейс репозитория для той же сущности определяется как:

public interface IMenuSecdRepository : IGenericRepository<MenuSecd>
{
    List<MenuSecd> GetItems(string usrgrp_id);
}

Класс репозитория для вышеупомянутого интерфейса:

public class MenuSecdRepository : GenericRepository<MenuSecd>, IMenuSecdRepository
{
    public MenuSecdRepository(DbContext context) : base(context)
    {

    }

    public List<MenuSecd> GetItems(string usrgrp_id)
    {
        return _dbset.Where(m => m.usrgrp_id == usrgrp_id).ToList();
    }
}

My DbContext выглядит следующим образом:

public class DashboardContext : DbContext
{
    public DashboardContext() : base("Name=DBEntities")
    {

    }

    public DbSet<MenuSecd> menusecd { get; set; }

    public override int SaveChanges()
    {
        var modifiedEntries = ChangeTracker.Entries().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);
        //future custom implementation like auditing
        return base.SaveChanges();
    }
}

Мой UnitOfWork выглядит следующим образом:

public sealed class UnitOfWork : IUnitOfWork
{
    private DbContext _dbContext;
    public UnitOfWork(DbContext context)
    {
        _dbContext = context;
    }

    public int Commit()
    {
        return _dbContext.SaveChanges();
    }

    //disposes current object
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    //disposes all external resources
    private void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_dbContext != null)
            {
                _dbContext.Dispose();
                _dbContext = null;
            }
        }
    }
}

Мой контроллер:

public class DashController : Controller
{
    private readonly IMenuSecdLogic _menuSecdLogic;
    public DashController(IMenuSecdLogic menuSecdLogic)
    {
         _menuSecdLogic = menuSecdLogic;          
    }
    public void Save()
    {
         var menuSecd = new menuSecd();
         //populate all fields for entity MenuSecd
         _menuSecdLogic.Create(menuSecd);
    }
}

My Unity Config в App_Start выглядит следующим образом:

public static void RegisterTypes(IUnityContainer container)
{
    container.RegisterType<DbContext, DashboardContext>();
    container.RegisterType<IUnitOfWork, UnitOfWork>();
    container.RegisterType(typeof(IGenericRepository<>), typeof(GenericRepository<>));
    container.RegisterType<IMenuSecdLogic, MenuSecdLogic>();
    container.RegisterType<IMenuSecdRepository, MenuSecdRepository>();
}

Так что при запуске над проектом все строится нормально.Но когда контроллер вызывает:

_menuSecdLogic.Create(menuSecd);

Он достигает Entity Logic и добавляет новую сущность в _repository по адресу:

_repository.Add(entity);
_unitOfWork.Commit();

Но когда он нажимает следующую строку, чтобы фактически сохранить его в базе данных, которая является:

return _dbContext.SaveChanges();

в файле UnitOfWork.cs.Он приходит к dashboardContext, где он, наконец, должен сохранить его в базе данных.Но он выполняет:

var modifiedEntries = ChangeTracker.Entries().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);
    return base.SaveChanges();

Но в базе данных ничего не меняется.Там не будет записи в базе данных.Чтобы протестировать, я добавил измененные записи, чтобы увидеть, находится ли он в контексте или нет.К тому времени, когда контроль достигает этой точки, я не вижу никаких измененных записей вообще.Но в EntityLogic.cs он добавляет новую сущность к локальным сущностям в хранилище.Я не уверен, что здесь происходит с UnitOfWork.Я запустил SQL Profiler, чтобы увидеть, попадает ли он в базу данных или нет.Интересно, что это не бьет по базе данных вообще.Но если я внесу следующие изменения в EntityLogic следующим образом:

public virtual void Create(T entity)
{
    if(entity == null)
    {
        throw new ArgumentNullException(nameof(entity));
    }

    _repository.Add(entity);
    _repository.Save();
    //_unitOfWork.Commit();
}

Он попадет в базу данных, и записи будут сохранены в порядке.Но я не понимаю, почему это не отслеживание изменений и не попадание в базу данных, если я использую _unitOfWork.Commit(), что я хочу сделать.Пожалуйста, помогите.

1 Ответ

0 голосов
/ 18 октября 2018

Похоже, ваша проблема - сфера вашей DbContext.Ваши UnitOfWork и GenericRepository<T> классы получают разные экземпляры.

Не очень знаком с Unity, но похоже, что вы хотите использовать что-то подобное для своей DbContext регистрации:

container.RegisterType<DbContext, DashboadContext>(new PerRequestLifetimeManager());

Это создаст один DashboardContext для каждого запроса, и ваши UnitOfWork и GenericRepository<T> классы будут работать в одном контексте.

...