使用 Unity 的 MVC 控制器构造函数注入中的工作单元和存储库模式不对数据库进行任何更改

Unit of Work and Repository Pattern in MVC controller constructor injection using Unity not doing any changes to database

1.) 我正在构建具有 3 层项目架构的新 MVC 应用程序:

  1. 带有实体的共同项目
  2. Business/Service 持有接口和逻辑 classes 和
  3. 数据存储库、接口、DbContextUnitOfWorkclasses。我正在使用 Unity Config 来注册依赖项,DbContextUnitOfWork.

2.) 我为每个 table 创建了一个存储库和一个执行基本 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);
}

实体逻辑Class:

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

通用项目中定义的实体的示例业务逻辑class:

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

上述接口的存储库 class 是:

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

我的 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);
    }
}

我在 App_Start 中的 Unity 配置看起来像:

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

它到达实体逻辑并将新实体添加到 _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();

但数据库中没有任何变化。数据库中不会有任何记录。为了测试,我添加了 modifiedEntries 以查看它是否在上下文中。当控制达到这一点时,我根本看不到任何修改过的条目。但在 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() 它既不跟踪更改也不访问数据库。请帮忙。

看起来你的问题是你的 DbContext 的范围。您的 UnitOfWorkGenericRepository<T> 类 获得不同的实例。

对 Unity 不太熟悉,但看起来您想使用类似这样的东西进行 DbContext 注册:

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

这将为每个请求创建一个 DashboardContext,并且您的 UnitOfWorkGenericRepository<T> 类 将在相同的上下文中工作。