c# - 使用 Unity 的 MVC 控制器构造函数注入中的工作单元和存储库模式不对数据库进行任何更改
问题描述
1.)我正在构建具有 3 层项目架构的新 MVC 应用程序,具有:
- 与实体的共同项目
- 业务/服务持有接口和逻辑类和
- 数据保存存储库、接口
DbContext
和UnitOfWork
类。我正在使用 Unity Config 来注册依赖项,DbContext
并且UnitOfWork
.
2.) 我为每个表创建了一个存储库和一个执行基本 CRUD 操作的通用存储库。
位于 Common Project 中的示例实体:
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();
}
}
Common Project 中定义的实体的示例业务逻辑类:
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();
}
}
我的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
. 您UnitOfWork
和GenericRepository<T>
班级正在获得不同的实例。
对 Unity 不太熟悉,但看起来您想使用类似这样的东西进行DbContext
注册:
container.RegisterType<DbContext, DashboadContext>(new PerRequestLifetimeManager());
DashboardContext
这将为每个请求创建一个,并且您UnitOfWork
和GenericRepository<T>
类将在相同的上下文中工作。
推荐阅读
- matlab - 我可以在 matlab R2016b 中使用什么来代替 substring() 函数
- c# - 签名可写 URL 出错:我们计算的请求签名与您提供的签名不匹配
- jquery - 如何创建 javascript/jquery 实时检查输入字段中的禁用词
- java - 用于单元测试的 spring-boot junit 负载测试属性资源
- ipv6 - 如何计算两个 IPv6 地址之间的地址数
- bash - Bash 字符串 while 循环
- ruby-on-rails - 如何在 RSPEC 中测试或存根 Sidekiq::Batch?
- python - 使用 Python GUI 添加整数时遇到问题
- reactjs - flow - 使用 Flow 进行输入的 react 路由器的 history.push 可以使用哪种类型?
- exoplayer - 对于 Exoplayer,我可以添加(或启用?)一个按钮来使用标准控件切换隐藏式字幕,例如在 PlayerControlView 中?