将多个DbContexts与通用存储库和工作单元一起使用
我的应用程序越来越大,到目前为止,我有一个MyDbContext
,它包含我在我的应用程序中需要的所有表。 我希望(为了概述)将它们分成多个DbContext
,如MainDbContext
, EstateModuleDbContext
, AnotherModuleDbContext
和UserDbContext
。
我不确定这是怎么做的可能因为我现在正在使用dependecy injection(ninject)将我的DbContext放在我的UnitOfWork类上,如:
kernel.Bind(typeof(IUnitOfWork)).To(typeof(UnitOfWork));
我是否应该通过dependency injection和显式设置我希望在我的服务上使用的DbContext
来删除此方法,例如:
private readonly EstateService _estateService; public HomeController() { IUnitOfWork uow = new UnitOfWork(); _estateService = new EstateService(uow); }
代替:
private readonly EstateService _estateService; public HomeController(IUnitOfWork uow) { _estateService = new EstateService(uow); }
或者这有另一种更好的方法吗? 另外作为一个附带问题,我不喜欢将uow
传递给我的服务 – 还有另一种(更好的)方法吗?
码
我有这个IDbContext和MyDbContext:
public interface IDbContext { DbSet Set() where T : class; DbEntityEntry Entry(T entity) where T : class; int SaveChanges(); void Dispose(); } public class MyDbContext : DbContext, IDbContext { public DbSet Table1 { get; set; } public DbSet Table1 { get; set; } public DbSet Table1 { get; set; } public DbSet Table1 { get; set; } public DbSet Table1 { get; set; } /* and so on */ static MyDbContext() { Database.SetInitializer(new CreateDatabaseIfNotExists()); } public MyDbContext() : base("MyDbContext") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { } }
然后我有这个IRepository和实现:
public interface IRepository where T : class { IQueryable GetAll(); void Add(T entity); void Delete(T entity); void DeleteAll(IEnumerable entity); void Update(T entity); bool Any(); } public class Repository : IRepository where T : class { private readonly IDbContext _context; private readonly IDbSet _dbset; public Repository(IDbContext context) { _context = context; _dbset = context.Set(); } public virtual IQueryable GetAll() { return _dbset; } public virtual void Add(T entity) { _dbset.Add(entity); } public virtual void Delete(T entity) { var entry = _context.Entry(entity); entry.State = EntityState.Deleted; _dbset.Remove(entity); } public virtual void DeleteAll(IEnumerable entity) { foreach (var ent in entity) { var entry = _context.Entry(ent); entry.State = EntityState.Deleted; _dbset.Remove(ent); } } public virtual void Update(T entity) { var entry = _context.Entry(entity); _dbset.Attach(entity); entry.State = EntityState.Modified; } public virtual bool Any() { return _dbset.Any(); } }
以及处理DbContext完成工作的IUnitOfWork和实现
public interface IUnitOfWork : IDisposable { IRepository GetRepository() where TEntity : class; void Save(); } public class UnitOfWork : IUnitOfWork where TContext : IDbContext, new() { private readonly IDbContext _ctx; private readonly Dictionary _repositories; private bool _disposed; public UnitOfWork() { _ctx = new TContext(); _repositories = new Dictionary(); _disposed = false; } public IRepository GetRepository() where TEntity : class { // Checks if the Dictionary Key contains the Model class if (_repositories.Keys.Contains(typeof(TEntity))) { // Return the repository for that Model class return _repositories[typeof(TEntity)] as IRepository; } // If the repository for that Model class doesn't exist, create it var repository = new Repository(_ctx); // Add it to the dictionary _repositories.Add(typeof(TEntity), repository); return repository; } public void Save() { _ctx.SaveChanges(); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (this._disposed) return; if (disposing) { _ctx.Dispose(); } this._disposed = true; } }
除非存在逻辑接缝,否则不要将模块化数据块拆分为多个DbContext
。 来自DbContextA
实体不能具有DbContextA
实体的自动导航或集合属性。 如果拆分上下文,则代码必须负责手动强制执行约束并在上下文之间加载相关数据。
为了“概述”(又名保持理智),您仍然可以按模块组织CLR代码和数据库表。 对于POCO,将它们保存在不同名称空间下的不同文件夹中。 对于表,您可以按模式进行分组。 (但是,在按照SQL模式进行组织时,您可能还应该考虑安全性因素。例如,如果有任何数据库用户应该对某些表具有受限访问权限,请根据这些规则设计模式。)然后,您可以执行此操作在构建模型时:
ToTable("TableName", "SchemaName"); // put table under SchemaName, not dbo
当它的实体与第一个DbContext
任何实体没有关系时,才使用单独的DbContext
。
我也同意Wiktor,因为我不喜欢你的界面和实现设计。 我特别不喜欢public interface IRepository
。 另外,为什么声明多个public DbSet
public DbSet
你的MyDbContext
? 请帮帮忙,阅读这篇文章 ,然后阅读本文 。
您可以使用以下EF界面设计大大简化代码:
interface IUnitOfWork { int SaveChanges(); } interface IQueryEntities { IQueryable Query (); // implementation returns Set ().AsNoTracking() IQueryable EagerLoad (IQueryable queryable, Expression> expression); // implementation returns queryable.Include(expression) } interface ICommandEntities : IQueryEntities, IUnitOfWork { T Find (params object[] keyValues); IQueryable FindMany (); // implementation returns Set () without .AsNoTracking() void Create (T entity); // implementation changes Entry(entity).State void Update (T entity); // implementation changes Entry(entity).State void Delete (T entity); // implementation changes Entry(entity).State void Reload (T entity); // implementation invokes Entry(entity).Reload }
如果声明MyDbContext : ICommandEntities
,则只需设置几个方法来实现接口(通常是单行)。 然后,您可以将3个接口中的任何一个注入到服务实现中:通常ICommandEntities
用于具有副作用的操作,而IQueryEntities
用于不具有副作用的操作。 任何只负责保存状态的服务(或服务修饰者)都可以依赖IUnitOfWork
。 我不同意Controller
应该依赖于IUnitOfWork
。 使用上述设计,您的服务应在返回Controller
之前保存更改。
如果你的应用程序中有多个单独的DbContext
类是有意义的,你可以像Wiktor建议的那样做 ,并使上述接口通用。 然后,您可以dependency injection服务,如下所示:
public SomeServiceClass(IQueryEntities users, ICommandEntities estateModule) { ... } public SomeControllerClass(SomeServiceClass service) { ... } // Ninject will automatically constructor inject service instance into controller // you don't need to pass arguments to the service constructor from controller
创建广泛的每聚合(甚至更糟的每个实体)存储库接口可以与EF对抗,繁殖无聊的管道代码,并过度注入构造函数。 相反,为您的服务提供更多灵活性。 像.Any()
这样的方法不属于接口,您可以在服务方法中调用Query
或FindMany
返回的IQueryable
上的扩展。
您的工作单元界面不是通用的,但实现方式是。 清理这个的最简单方法是决定并遵循相同的惯例。
例如,也使您的界面通用。 这样,您可以将三个不同的接口(具有三个不同通用参数的相同接口)注册到三个不同的实现:
container.Bind( typeof> ).To( typeof> ); ...
是的,将您的工作单元注入控制器/服务是个好主意。
上述就是C#学习教程:将多个DbContexts与通用存储库和工作单元一起使用分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1015734.html