using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Data; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Threading.Tasks; using VOL.Core.Configuration; using VOL.Core.Dapper; using VOL.Core.DBManager; using VOL.Core.EFDbContext; using VOL.Core.Enums; using VOL.Core.Extensions; using VOL.Core.Services; using VOL.Core.Utilities; using VOL.Entity; using VOL.Entity.SystemModels; namespace VOL.Core.BaseProvider { public abstract class RepositoryBase where TEntity : BaseEntity { public RepositoryBase() { } public RepositoryBase(BaseDbContext dbContext) { DefaultDbContext = dbContext ?? throw new Exception("dbContext未实例化。"); } private BaseDbContext DefaultDbContext { get; set; } private BaseDbContext EFContext { get { return DefaultDbContext; } } public virtual BaseDbContext DbContext { get { return DefaultDbContext; } } private DbSet DBSet { get { return EFContext.Set(); } } private ISqlDapper _dapper = null; public ISqlDapper DapperContext { get { _dapper ??= DBServerProvider.GetSqlDapper(); return _dapper; } } /// /// 执行事务 /// /// 如果返回false则回滚事务(可自行定义规则) /// public virtual WebResponseContent DbContextBeginTransaction(Func action) { if (DefaultDbContext.Database.CurrentTransaction != null) return action(); WebResponseContent webResponse = new WebResponseContent(); using IDbContextTransaction transaction = DefaultDbContext.Database.BeginTransaction(); try { webResponse = action(); if (webResponse.Status) { transaction.Commit(); } else { transaction.Rollback(); } return webResponse; } catch (Exception ex) { transaction.Rollback(); string message = ex.Message + ex?.InnerException + ex?.StackTrace; if (HttpContext.Current.GetService().IsDevelopment()) { return webResponse.Error(message); } Logger.Error(message); return webResponse.Error("处理异常"); } } public virtual async Task DbContextBeginTransactionAsync(Func> action) { if (DefaultDbContext.Database.CurrentTransaction != null) return await action(); WebResponseContent webResponse = new WebResponseContent(); using IDbContextTransaction transaction = await DefaultDbContext.Database.BeginTransactionAsync(); try { webResponse = await action(); if (webResponse.Status) { await transaction.CommitAsync(); } else { await transaction.RollbackAsync(); } return webResponse; } catch (Exception ex) { await transaction.RollbackAsync(); string message = ex.Message + ex?.InnerException + ex?.StackTrace; if (HttpContext.Current.GetService().IsDevelopment()) { return webResponse.Error(message); } Logger.Error(message); return webResponse.Error("处理异常"); } } public virtual bool Exists(Expression> predicate, bool filterDeleted = true) where TExists : class { return EFContext.Set().Any(predicate); } public virtual Task ExistsAsync(Expression> predicate, bool filterDeleted = true) where TExists : class { return EFContext.Set(filterDeleted).AnyAsync(predicate); } public virtual bool Exists(Expression> predicate, bool filterDeleted = true) { return EFContext.Set(filterDeleted).Any(predicate); } public virtual Task ExistsAsync(Expression> predicate, bool filterDeleted = true) { return EFContext.Set(filterDeleted).AnyAsync(predicate); } /// /// 查询字段不为null或者为空 /// /// x=>new {x.字段} /// 查询的类 /// 查询类型 /// public virtual IQueryable WhereIF([NotNull] Expression> field, string value, LinqExpressionType linqExpression = LinqExpressionType.Equal) { return EFContext.Set().WhereNotEmpty(field, value, linqExpression); } public virtual IQueryable WhereIF(bool checkCondition, Expression> predicate) { if (checkCondition) { return EFContext.Set().Where(predicate); } return EFContext.Set(); } public virtual IQueryable WhereIF(bool checkCondition, Expression> predicate) where T : class { if (checkCondition) { return EFContext.Set().Where(predicate); } return EFContext.Set(); } public virtual TFind FindById(object id) where TFind : class { return EFContext.FindById(id); } public virtual async Task FindByIdAsync(List id) where TFind : class { return await EFContext.FindByIdAsync(id); } public virtual List Find(Expression> predicate, bool filterDeleted = true) where TFind : class { return EFContext.Set(filterDeleted).Where(predicate).ToList(); } public virtual Task FindAsyncFirst(Expression> predicate, bool filterDeleted = true) where TFind : class { return FindAsIQueryable(predicate, filterDeleted).FirstOrDefaultAsync(); } public virtual Task FindAsyncFirst(Expression> predicate, bool filterDeleted = true) { return FindAsIQueryable(predicate, filterDeleted).FirstOrDefaultAsync(); } public virtual Task> FindAsync(Expression> predicate, bool filterDeleted = true) where TFind : class { return FindAsIQueryable(predicate, filterDeleted).ToListAsync(); } public virtual Task> FindAsync(Expression> predicate, bool filterDeleted = true) { return FindAsIQueryable(predicate, filterDeleted).ToListAsync(); } public virtual Task FindFirstAsync(Expression> predicate, bool filterDeleted = true) { return FindAsIQueryable(predicate, filterDeleted).FirstOrDefaultAsync(); } public virtual Task> FindAsync(Expression> predicate, Expression> selector, bool filterDeleted = true) { return FindAsIQueryable(predicate, filterDeleted).Select(selector).ToListAsync(); } public virtual Task FindFirstAsync(Expression> predicate, Expression> selector, bool filterDeleted = true) { return FindAsIQueryable(predicate, filterDeleted).Select(selector).FirstOrDefaultAsync(); } private IQueryable FindAsIQueryable(Expression> predicate, bool filterDeleted = true) where TFind : class { return EFContext.Set(filterDeleted).Where(predicate); } public virtual List Find(Expression> predicate, Expression> selector, bool filterDeleted = true) { return EFContext.Set(filterDeleted).Where(predicate).Select(selector).ToList(); } /// /// 单表查询 /// /// /// public virtual List Find(Expression> predicate, bool filterDeleted = true) { return FindAsIQueryable(predicate, filterDeleted).ToList(); } /// /// /// /// /// /// 排序字段 /// public virtual TEntity FindFirst(Expression> predicate, bool filterDeleted = true) { return EFContext.Set(filterDeleted).Where(predicate).FirstOrDefault(); } public IQueryable FindAsIQueryable(Expression> predicate, Expression>> orderBy = null, bool filterDeleted = true) { if (orderBy != null) return DbContext.Set(filterDeleted).Where(predicate).GetIQueryableOrderBy(orderBy.GetExpressionToDic()); return DbContext.Set(filterDeleted).Where(predicate); } public IIncludableQueryable Include(Expression> incluedProperty) { return DbContext.Set().Include(incluedProperty); } /// /// 通过条件查询返回指定列的数据(将TEntity映射到匿名或实体T) ///var result = Sys_UserRepository.GetInstance.Find(x => x.UserName == loginInfo.userName, p => new { uname = p.UserName }); /// /// /// /// /// /// /// /// 查询条件 /// 多个排序字段key为字段,value为升序/降序 /// public virtual IQueryable IQueryablePage(int pageIndex, int pagesize, out int rowcount, Expression> predicate, Expression>> orderBy, bool returnRowCount = true) where TFind : class { pageIndex = pageIndex <= 0 ? 1 : pageIndex; pagesize = pagesize <= 0 ? 10 : pagesize; if (predicate == null) { predicate = x => 1 == 1; } var _db = DbContext.Set(); rowcount = returnRowCount ? _db.Count(predicate) : 0; return DbContext.Set().Where(predicate) .GetIQueryableOrderBy(orderBy.GetExpressionToDic()) .Skip((pageIndex - 1) * pagesize) .Take(pagesize); } /// /// 分页排序 /// /// /// /// /// /// /// public virtual IQueryable IQueryablePage(IQueryable queryable, int pageIndex, int pagesize, out int rowcount, Dictionary orderBy, bool returnRowCount = true) { pageIndex = pageIndex <= 0 ? 1 : pageIndex; pagesize = pagesize <= 0 ? 10 : pagesize; rowcount = returnRowCount ? queryable.Count() : 0; return queryable.GetIQueryableOrderBy(orderBy) .Skip((pageIndex - 1) * pagesize) .Take(pagesize); } /// /// 更新表数据 /// /// /// 是否保存 /// 格式 Expression> expTree = x => new { x.字段1, x.字段2 }; public virtual int Update(TEntity entity, Expression> properties, bool saveChanges = false) { return Update(entity, properties, saveChanges); } public virtual int Update(TSource entity, Expression> properties, bool saveChanges = false) where TSource : class { return UpdateRange(new List { entity }, properties, saveChanges); } public virtual int Update(TSource entity, string[] properties, bool saveChanges = false) where TSource : class { return UpdateRange(new List() { entity }, properties, saveChanges); } public virtual int Update(TSource entity, bool saveChanges = false) where TSource : class { return UpdateRange(new List() { entity }, new string[0], saveChanges); } public virtual int UpdateRange(IEnumerable entities, Expression> properties, bool saveChanges = false) where TSource : class { return UpdateRange(entities, properties?.GetExpressionProperty(), saveChanges); } public virtual int UpdateRange(IEnumerable entities, bool saveChanges = false) where TSource : class { return UpdateRange(entities, new string[0], saveChanges); } /// /// 更新表数据 /// /// /// 格式 Expression> expTree = x => new { x.字段1, x.字段2 }; public int UpdateRange(IEnumerable entities, string[] properties, bool saveChanges = false) where TSource : class { if (properties != null && properties.Length > 0) { PropertyInfo[] entityProperty = typeof(TSource).GetProperties() .Where(x => x.GetCustomAttribute() == null && !(x.PropertyType.IsGenericType && x.PropertyType.GetGenericTypeDefinition() == typeof(List<>))).ToArray(); string keyName = entityProperty.GetKeyName(); if (properties.Contains(keyName)) { properties = properties.Where(x => x != keyName).ToArray(); } properties = properties.Where(x => entityProperty.Select(s => s.Name).Contains(x)).ToArray(); } foreach (TSource item in entities) { if (properties == null || properties.Length == 0) { DbContext.Entry(item).State = EntityState.Modified; continue; } var entry = DbContext.Entry(item); properties.ToList().ForEach(x => { entry.Property(x).IsModified = true; }); } if (!saveChanges) return 0; //2020.04.24增加更新时并行重试处理 try { // Attempt to save changes to the database return DbContext.SaveChanges(); } catch (DbUpdateConcurrencyException ex) { int affectedRows = 0; foreach (var entry in ex.Entries) { var proposedValues = entry.CurrentValues; var databaseValues = entry.GetDatabaseValues(); //databaseValues == null说明数据已被删除 if (databaseValues != null) { foreach (var property in properties == null || properties.Length == 0 ? proposedValues.Properties : proposedValues.Properties.Where(x => properties.Contains(x.Name))) { var proposedValue = proposedValues[property]; var databaseValue = databaseValues[property]; } affectedRows++; entry.OriginalValues.SetValues(databaseValues); } } if (affectedRows == 0) return 0; return DbContext.SaveChanges(); } } /// /// /// /// /// 是否修改明细 /// 是否删除明细不存在的数据 /// 主表指定修改字段 /// 明细指定修改字段 /// 是否保存 /// public virtual WebResponseContent UpdateRange(TEntity entity, bool updateDetail = false, bool delNotExist = false, Expression> updateMainFields = null, Expression> updateDetailFields = null, bool saveChange = false) where Detail : class { WebResponseContent webResponse = new WebResponseContent(); Update(entity, updateMainFields); string message = ""; if (updateDetail) { PropertyInfo[] properties = typeof(TEntity).GetProperties(); PropertyInfo detail = properties.Where(x => x.PropertyType.Name == "List`1").ToList().FirstOrDefault(); if (detail != null) { PropertyInfo key = properties.GetKeyProperty(); object obj = detail.GetValue(entity); Type detailType = typeof(TEntity).GetCustomAttribute().DetailTable[0]; message = UpdateDetail(obj as List, key.Name, key.GetValue(entity), updateDetailFields, delNotExist); } } if (!saveChange) return webResponse.OK(); DbContext.SaveChanges(); return webResponse.OK("修改成功,明细" + message, entity); } private string UpdateDetail(List list, string keyName, object keyValue, Expression> updateDetailFields = null, bool delNotExist = false) where TDetail : class { if (list == null) return ""; PropertyInfo property = typeof(TDetail).GetKeyProperty(); string detailKeyName = property.Name; DbSet details = DbContext.Set(); Expression> selectExpression = detailKeyName.GetExpression(); Expression> whereExpression = keyName.CreateExpression(keyValue, LinqExpressionType.Equal); List detailKeys = details.Where(whereExpression).Select(selectExpression).ToList(); //获取主键默认值 string keyDefaultVal = property.PropertyType .Assembly .CreateInstance(property.PropertyType.FullName).ToString(); int addCount = 0; int editCount = 0; int delCount = 0; PropertyInfo mainKeyProperty = typeof(TDetail).GetProperty(keyName); List keys = new List(); list.ForEach(x => { var set = DbContext.Set(); object val = property.GetValue(x); //主键是默认值的为新增的数据 if (val.ToString() == keyDefaultVal) { x.SetCreateDefaultVal(); //设置主表的值,也可以不设置 mainKeyProperty.SetValue(x, keyValue); details.Add(x); addCount++; } else//修改的数据 { //获取所有修改的key,如果从数据库查来的key,不在修改中的key,则为删除的数据 keys.Add(val); x.SetModifyDefaultVal(); Update(x, updateDetailFields); // repository.DbContext.Entry(x).State = EntityState.Modified; editCount++; } }); //删除 if (delNotExist) { detailKeys.Where(x => !keys.Contains(x)).ToList().ForEach(d => { delCount++; TDetail detail = Activator.CreateInstance(); property.SetValue(detail, d); DbContext.Entry(detail).State = EntityState.Deleted; for (int i = 0; i < list.Count(); i++) { if (property.GetValue(list[i]) == d) { list.RemoveAt(i); } } }); } return $"修改[{editCount}]条,新增[{addCount}]条,删除[{delCount}]条"; } public virtual void Delete(TEntity model, bool saveChanges) { DBSet.Remove(model); if (saveChanges) { DbContext.SaveChanges(); } } /// /// 通过主键批量删除 /// /// 主键key /// 是否连明细一起删除 /// public virtual int DeleteWithKeys(object[] keys, bool saveChange = false) { var keyPro = typeof(TEntity).GetKeyProperty(); foreach (var key in keys.Distinct()) { TEntity entity = Activator.CreateInstance(); keyPro.SetValue(entity, key.ChangeType(keyPro.PropertyType)); DbContext.Entry(entity).State = EntityState.Deleted; } if (saveChange) { DbContext.SaveChanges(); } return keys.Length; } public virtual int Delete([NotNull] Expression> wheres, bool saveChange = true) { return Delete(wheres, saveChange); } public virtual int Delete([NotNull] Expression> wheres, bool saveChange = true) where T : class { return DbContext.Set().Where(wheres).ExecuteDelete(); } public virtual Task AddAsync(TEntity entities) { return DBSet.AddRangeAsync(entities); } public virtual Task AddRangeAsync(IEnumerable entities) { return DBSet.AddRangeAsync(entities); } public virtual void Add(TEntity entities, bool saveChanges = false) { AddRange([entities], saveChanges); } public virtual void Add(T entity, bool saveChanges = false) where T : class { AddRange([entity], saveChanges); } public virtual void AddRange(IEnumerable entities, bool saveChanges = false) { AddRange(entities, saveChanges); } public virtual void AddRange(IEnumerable entities, bool saveChanges = false) where T : class { if (entities.Count() == 0) { return; } if (AppSetting.EnableSnowFlakeID) { PropertyInfo keyPro = typeof(T).GetKeyProperty(); if (keyPro.PropertyType == typeof(long)) { //生成雪花id var idWorker = new IdWorker(); foreach (var item in entities) { if (keyPro.GetValue(item).ToString().Length < 10) { keyPro.SetValue(item, idWorker.NextId()); } } } } DbContext.Set().AddRange(entities); if (saveChanges) DbContext.SaveChanges(); } public virtual int SaveChanges() { return EFContext.SaveChanges(); } public virtual Task SaveChangesAsync() { return EFContext.SaveChangesAsync(); } public virtual int ExecuteSqlCommand(string sql, params SqlParameter[] sqlParameters) { return DbContext.Database.ExecuteSqlRaw(sql, sqlParameters); } public virtual List FromSql(string sql, params SqlParameter[] sqlParameters) { return DBSet.FromSqlRaw(sql, sqlParameters).ToList(); } /// /// 执行sql /// 使用方式 FormattableString sql=$"select * from xx where name ={xx} and pwd={xx1} ", /// FromSqlInterpolated内部处理sql注入的问题,直接在{xx}写对应的值即可 /// 注意:sql必须 select * 返回所有TEntity字段, /// /// /// public virtual IQueryable FromSqlInterpolated([NotNull] FormattableString sql) { return DBSet.FromSqlInterpolated(sql); } /// /// 取消上下文跟踪 /// /// public virtual void Detached(TEntity entity) { DbContext.Entry(entity).State = EntityState.Detached; } public virtual void DetachedRange(IEnumerable entities) { foreach (var entity in entities) { DbContext.Entry(entity).State = EntityState.Detached; } } } }