搭建自己的框架WedeNet(二)
WedeNet2018.Infrastructure-基础设施层:
结构如下:
Tools结构如下:
考虑到系统可能会有多个数据上下文(暂时以两个为例),所以根据需要定义两个T4模板用来生成对应的entities和dbcontext类,每个T4模板对应一个数据库连接,这些数据库连接配置在应用层的配置文件中(如UI层web.config或者WCF寄宿层的app.config)。
生成的结果如下:
在此,我把UnitOfWork和Repository都看做为组件,和它们所依赖的dbcontext都统一放在了Components目录下。
仓储需要包装不同的EF entitiy,自然需要定义为泛型接口,如下:
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace WedeNet2018.Infrastructure.Components { public interface IRepository<T> where T : class { IQueryable<T> All(); IQueryable<T> Filter(Expression<Func<T, bool>> predicate); T Find(params object[] keys); T Find(Expression<Func<T, bool>> predicate); void Insert(T t); void Insert(IEnumerable<T> entities); void Delete(T t); void Delete(IEnumerable<T> entities); void Update(T t); void Update(IEnumerable<T> entities); void Clear(); } }
接口的实现如下:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace WedeNet2018.Infrastructure.Components { public class EntityRepository<TContext,TEntity> : IRepository<TEntity> where TContext : DbContext where TEntity : class { protected TContext context; protected DbSet<TEntity> dbSet; public EntityRepository(TContext dbContext) { context = dbContext; dbSet = context.Set<TEntity>(); } protected virtual TContext Context { get { return context; } } protected virtual DbSet<TEntity> DbSet { get { return dbSet; } } /// <summary> /// 查询全部当前实体数据集 /// </summary> /// <returns>IQueryable集合</returns> public virtual IQueryable<TEntity> All() { return DbSet.AsQueryable(); } /// <summary> /// 条件查询当前实体数据集 /// </summary> /// <param name="predicate">查询条件</param> /// <returns>IQueryable集合</returns> public virtual IQueryable<TEntity> Filter(Expression<Func<TEntity, bool>> predicate) { return DbSet.Where(predicate).AsQueryable<TEntity>(); } /// <summary> /// 查找指定主键的数据 /// </summary> /// <param name="keys">指定主键</param> /// <returns>符合编号的记录,不存在返回null </returns> public virtual TEntity Find(params object[] keys) { return DbSet.Find(keys); } /// <summary> /// 查找指定条件的单条数据 /// </summary> /// <param name="predicate">查询条件</param> /// <returns>返回符合条件的数据,或者null</returns> public virtual TEntity Find(Expression<Func<TEntity, bool>> predicate) { return DbSet.FirstOrDefault(predicate); } /// <summary> /// 上下文中插入单个实体 /// </summary> /// <param name="entity"></param> public virtual void Insert(TEntity entity) { if (Context.Entry(entity).State == EntityState.Detached) { Context.Entry(entity).State = EntityState.Added; //DbSet.Add(entity); } } /// <summary> /// 上下文中批量插入实体 /// </summary> /// <param name="entities"></param> public virtual void Insert(IEnumerable<TEntity> entities) { try { Context.Configuration.AutoDetectChangesEnabled = false; foreach (TEntity entity in entities) { Insert(entity); } } finally { Context.Configuration.AutoDetectChangesEnabled = true; } } /// <summary> /// 上下文中删除单个实体 /// </summary> /// <param name="entity"></param> public virtual void Delete(TEntity entity) { if (Context.Entry(entity).State == EntityState.Detached) { DbSet.Attach(entity); } DbSet.Remove(entity); } /// <summary> /// 上下文中批量删除实体 /// </summary> /// <param name="entities"></param> public virtual void Delete(IEnumerable<TEntity> entities) { try { Context.Configuration.AutoDetectChangesEnabled = false; foreach (TEntity entity in entities) { Delete(entity); } } finally { Context.Configuration.AutoDetectChangesEnabled = true; } } /// <summary> /// 上下文中更新单个实体 /// </summary> /// <param name="entity"></param> public virtual void Update(TEntity entity) { if (Context.Entry(entity).State == EntityState.Detached) { DbSet.Attach(entity); } Context.Entry(entity).State = EntityState.Modified; } /// <summary> /// 上下文中批量更新实体 /// </summary> /// <param name="entities"></param> public virtual void Update(IEnumerable<TEntity> entities) { try { Context.Configuration.AutoDetectChangesEnabled = false; foreach (TEntity entity in entities) { Update(entity); } } finally { Context.Configuration.AutoDetectChangesEnabled = true; } } public virtual void Clear() { } } }
在这个仓储基类里,引入了该仓储依赖的dbcontext,这个dbcontext会在系统初始化该仓储的时候传入,并且是单例的。这样才能保证UnitOfWork操作的一致性。
另外,针对不同的dbcontext,我也定义了对应的抽象类,如:
目的是在做IOC的时候一个具体类型必须对应一个基类,而在这两个抽象类内部都继承了DbContext,如:
// <auto-generated> // 此代码由工具生成。 // 对此文件的更改可能会导致不正确的行为,并且如果 // 重新生成代码,这些更改将会丢失。 // 如存在本生成代码外的新需求,请在相同命名空间下创建同名分部类进行实现。 // </auto-generated> using System; using System.Collections.Generic; using System.Linq; using System.Data.Entity; using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations; namespace WedeNet2018.Infrastructure { public abstract class AbsWedeDBContex:DbContext { //连接字符串名称:基于Config文件中连接字符串的配置 const string connectionStringName = "constring"; public AbsWedeDBContex() : base(connectionStringName) { } } }
接下来就是UnitOfWork,接口定义如下:
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace WedeNet2018.Infrastructure.Components { /// <summary> /// 定义工作单元统一接口 /// </summary> public interface IUnitOfWorks { IQueryable<T> Where<T>(Expression<Func<T, bool>> predicate) where T : class; IQueryable<T> All<T>() where T : class; T Find<T>(object id) where T : class; T Find<T>(Expression<Func<T, bool>> predicate) where T : class; void Add<T>(T t) where T : class; void Add<T>(IEnumerable<T> items) where T : class; void Update<T>(T t) where T : class; void Update<T>(IEnumerable<T> items) where T : class; void Delete<T>(T t) where T : class; void Delete<T>(IEnumerable<T> items) where T : class; void Clear<T>() where T : class; bool IsCommitted { get; } int Commit(); } }
和上面定义了两个dbcontext抽象基类一样,出于IOC考虑,这里也定义了两个实现了IUnitOfWorks接口的接口,如:
下面是对应的实现类,如:
using System; using System.Collections.Generic; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Data.SqlClient; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; using WedeNet2018.Common; namespace WedeNet2018.Infrastructure.Components { /// <summary> /// 实现一个工作单元,将使用NInject注册为单例 /// </summary> /// <typeparam name="TDBContext">该工作单元使用的数据上下文类型</typeparam> public class XF0816UnitOfWorks<TDBContext> : IXF0816UnitOfWorks, IDisposable where TDBContext : DbContext { protected TDBContext dbContext; public XF0816UnitOfWorks(TDBContext context) { dbContext = context; } //构造通用的Repository private IDictionary<Type, object> repositoryTable = new Dictionary<Type, object>(); //注册其它的Repository public void Register<T>(IRepository<T> repository) where T : class { var key = typeof(T); if (!repositoryTable.ContainsKey(key)) repositoryTable.Add(key, repository); } private IRepository<T> GetRepository<T>() where T : class { IRepository<T> repository = null; var key = typeof(T); if (repositoryTable.ContainsKey(key)) repository = (IRepository<T>)repositoryTable[key]; else { repository = GenericRepository<T>(); repositoryTable.Add(key, repository); } return repository; } protected virtual IRepository<T> GenericRepository<T>() where T : class { return new EntityRepository<TDBContext, T>(dbContext); } /// <summary> /// 条件查询当前实体数据集 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="predicate">查询条件</param> /// <returns>IQueryable集合</returns> public System.Linq.IQueryable<T> Where<T>(Expression<Func<T, bool>> predicate) where T : class { return GetRepository<T>().Filter(predicate); } /// <summary> /// 查询全部当前实体数据集 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <returns>IQueryable集合</returns> public System.Linq.IQueryable<T> All<T>() where T : class { return GetRepository<T>().All(); } /// <summary> /// 查找指定主键的数据 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="id">实体主键</param> /// <returns>符合编号的记录,不存在返回null</returns> public T Find<T>(object id) where T : class { return GetRepository<T>().Find(id); } /// <summary> /// 查找指定条件的单条数据 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="predicate">查询条件</param> /// <returns>返回符合条件的数据,或者null</returns> public T Find<T>(Expression<Func<T, bool>> predicate) where T : class { return GetRepository<T>().Find(predicate); } /// <summary> /// 上下文中插入单个实体 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="t">实体</param> public void Add<T>(T t) where T : class { GetRepository<T>().Insert(t); } /// <summary> /// 上下文中批量插入实体 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="items">实体集合</param> public void Add<T>(IEnumerable<T> items) where T : class { GetRepository<T>().Insert(items); } /// <summary> /// 上下文中更新单个实体 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="t">实体</param> public void Update<T>(T t) where T : class { GetRepository<T>().Update(t); } /// <summary> /// 上下文中批量更新实体 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="items">实体集合</param> public void Update<T>(IEnumerable<T> items) where T : class { GetRepository<T>().Update(items); } /// <summary> /// 上下文中删除单个实体 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="t">实体</param> public void Delete<T>(T t) where T : class { GetRepository<T>().Delete(t); } /// <summary> /// 上下文中批量删除实体 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="items">实体集合</param> public void Delete<T>(IEnumerable<T> items) where T : class { GetRepository<T>().Delete(items); } public void Clear<T>() where T : class { GetRepository<T>().Clear(); } /// <summary> /// 当前单元操作是否已被提交 /// </summary> public bool IsCommitted { get; private set; } /// <summary> /// 提交当前工作单元 /// </summary> /// <returns></returns> public int Commit() { try { int result = dbContext.SaveChanges(); return result; } catch (DbUpdateException e) { if (e.InnerException != null && e.InnerException.InnerException is SqlException) { SqlException sqlEx = e.InnerException.InnerException as SqlException; string msg = SqlDataHelper.GetSqlExceptionMessage(sqlEx.Number); throw PublicHelper.ThrowDataAccessException("提交数据更新时发生异常:" + msg, sqlEx); } throw; } } public void Dispose() { if (dbContext != null) { dbContext.Dispose(); } GC.SuppressFinalize(this); } } }
到此为止,Infrastructure-基础设施层已经构建好了。