using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Storage; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Threading.Tasks; using WIDESEA_Core.Dapper; using WIDESEA_Core.DBManager; using WIDESEA_Core.EFDbContext; using WIDESEA_Core.Enums; using WIDESEA_Core.Extensions; using WIDESEA_Core.Utilities; using WIDESEA_Entity; using WIDESEA_Entity.SystemModels; namespace WIDESEA_Core.BaseProvider { public abstract class RepositoryBase<TEntity> where TEntity : BaseEntity { public RepositoryBase() { } public RepositoryBase(VOLContext dbContext) { this.DefaultDbContext = dbContext ?? throw new Exception("dbContext未实例化。"); } private VOLContext DefaultDbContext { get; set; } private VOLContext EFContext { get { DBServerProvider.GetDbContextConnection<TEntity>(DefaultDbContext); return DefaultDbContext; } } public virtual VOLContext DbContext { get { return DefaultDbContext; } } private DbSet<TEntity> DBSet { get { return EFContext.Set<TEntity>(); } } public ISqlDapper DapperContext { get { return DBServerProvider.GetSqlDapper<TEntity>(); } } /// <summary> /// 执行事务 /// </summary> /// <param name="action">如果返回false则回滚事务(å¯è‡ªè¡Œå®šä¹‰è§„则)</param> /// <returns></returns> public virtual WebResponseContent DbContextBeginTransaction(Func<WebResponseContent> 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(); return new WebResponseContent().Error(ex.Message); } } } public virtual bool Exists<TExists>(Expression<Func<TExists, bool>> predicate) where TExists : class { return EFContext.Set<TExists>().Any(predicate); } public virtual Task<bool> ExistsAsync<TExists>(Expression<Func<TExists, bool>> predicate) where TExists : class { return EFContext.Set<TExists>().AnyAsync(predicate); } public virtual bool Exists(Expression<Func<TEntity, bool>> predicate) { return DBSet.Any(predicate); } public virtual Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate) { return DBSet.AnyAsync(predicate); } public virtual List<TFind> Find<TFind>(Expression<Func<TFind, bool>> predicate) where TFind : class { return EFContext.Set<TFind>().Where(predicate).ToList(); } public virtual Task<TFind> FindAsyncFirst<TFind>(Expression<Func<TFind, bool>> predicate) where TFind : class { return FindAsIQueryable<TFind>(predicate).FirstOrDefaultAsync(); } public virtual Task<TEntity> FindAsyncFirst(Expression<Func<TEntity, bool>> predicate) { return FindAsIQueryable<TEntity>(predicate).FirstOrDefaultAsync(); } public virtual Task<List<TFind>> FindAsync<TFind>(Expression<Func<TFind, bool>> predicate) where TFind : class { return FindAsIQueryable<TFind>(predicate).ToListAsync(); } public virtual Task<List<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate) { return FindAsIQueryable(predicate).ToListAsync(); } public virtual Task<TEntity> FindFirstAsync(Expression<Func<TEntity, bool>> predicate) { return FindAsIQueryable(predicate).FirstOrDefaultAsync(); } public virtual Task<List<T>> FindAsync<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector) { return FindAsIQueryable(predicate).Select(selector).ToListAsync(); } public virtual Task<T> FindFirstAsync<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector) { return FindAsIQueryable(predicate).Select(selector).FirstOrDefaultAsync(); } public virtual IQueryable<TFind> FindAsIQueryable<TFind>(Expression<Func<TFind, bool>> predicate) where TFind : class { return EFContext.Set<TFind>().Where(predicate); } public virtual List<TEntity> Find<Source>(IEnumerable<Source> sources, Func<Source, Expression<Func<TEntity, bool>>> predicate) where Source : class { return FindAsIQueryable(sources, predicate).ToList(); } public virtual List<TResult> Find<Source, TResult>(IEnumerable<Source> sources, Func<Source, Expression<Func<TEntity, bool>>> predicate, Expression<Func<TEntity, TResult>> selector) where Source : class { return FindAsIQueryable(sources, predicate).Select(selector).ToList(); } /// <summary> /// 多æ¡ä»¶æŸ¥è¯¢ /// </summary> /// <typeparam name="Source"></typeparam> /// <param name="sources"></param> /// <param name="predicate"></param> /// <returns></returns> public virtual IQueryable<TEntity> FindAsIQueryable<Source>(IEnumerable<Source> sources, Func<Source, Expression<Func<TEntity, bool>>> predicate) where Source : class { // EFContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.TrackAll; Expression<Func<TEntity, bool>> resultPredicate = x => 1 == 2; foreach (Source source in sources) { Expression<Func<TEntity, bool>> expression = predicate(source); resultPredicate = (resultPredicate).Or_<TEntity>((expression)); } return EFContext.Set<TEntity>().Where(resultPredicate); } public virtual List<T> Find<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector) { return DBSet.Where(predicate).Select(selector).ToList(); } /// <summary> /// å•表查询 /// </summary> /// <param name="predicate"></param> /// <returns></returns> public virtual List<TEntity> Find(Expression<Func<TEntity, bool>> predicate) { return FindAsIQueryable(predicate).ToList(); } /// <summary> /// /// </summary> /// <param name="predicate"></param> /// <param name=""></param> /// <param name="orderBy">排åºå—段</param> /// <returns></returns> public virtual TEntity FindFirst(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, Dictionary<object, QueryOrderBy>>> orderBy = null) { return FindAsIQueryable(predicate, orderBy).FirstOrDefault(); } public IQueryable<TEntity> FindAsIQueryable(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, Dictionary<object, QueryOrderBy>>> orderBy = null) { if (orderBy != null) return DbContext.Set<TEntity>().Where(predicate).GetIQueryableOrderBy(orderBy.GetExpressionToDic()); return DbContext.Set<TEntity>().Where(predicate); } public IIncludableQueryable<TEntity, TProperty> Include<TProperty>(Expression<Func<TEntity, TProperty>> incluedProperty) { return DbContext.Set<TEntity>().Include(incluedProperty); } /// <summary> /// 通过æ¡ä»¶æŸ¥è¯¢è¿”回指定列的数æ®(å°†TEntityæ˜ å°„åˆ°åŒ¿åæˆ–实体T) ///var result = Sys_UserRepository.GetInstance.Find(x => x.UserName == loginInfo.userName, p => new { uname = p.UserName }); /// <summary> /// /// </summary> /// <typeparam name="TKey"></typeparam> /// <param name="pageIndex"></param> /// <param name="pagesize"></param> /// <param name="rowcount"></param> /// <param name="predicate">查询æ¡ä»¶</param> /// <param name="orderBySelector">多个排åºå—段keyä¸ºå—æ®µï¼Œvalue为å‡åº/é™åº</param> /// <returns></returns> public virtual IQueryable<TFind> IQueryablePage<TFind>(int pageIndex, int pagesize, out int rowcount, Expression<Func<TFind, bool>> predicate, Expression<Func<TEntity, Dictionary<object, QueryOrderBy>>> 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<TFind>(); rowcount = returnRowCount ? _db.Count(predicate) : 0; return DbContext.Set<TFind>().Where(predicate) .GetIQueryableOrderBy(orderBy.GetExpressionToDic()) .Skip((pageIndex - 1) * pagesize) .Take(pagesize); } /// <summary> /// åˆ†é¡µæŽ’åº /// </summary> /// <param name="queryable"></param> /// <param name="pageIndex"></param> /// <param name="pagesize"></param> /// <param name="rowcount"></param> /// <param name="orderBy"></param> /// <returns></returns> public virtual IQueryable<TEntity> IQueryablePage(IQueryable<TEntity> queryable, int pageIndex, int pagesize, out int rowcount, Dictionary<string, QueryOrderBy> orderBy, bool returnRowCount = true) { pageIndex = pageIndex <= 0 ? 1 : pageIndex; pagesize = pagesize <= 0 ? 10 : pagesize; rowcount = returnRowCount ? queryable.Count() : 0; return queryable.GetIQueryableOrderBy<TEntity>(orderBy) .Skip((pageIndex - 1) * pagesize) .Take(pagesize); } public virtual List<TResult> QueryByPage<TResult>(int pageIndex, int pagesize, out int rowcount, Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, Dictionary<object, QueryOrderBy>>> orderBy, Expression<Func<TEntity, TResult>> selectorResult, bool returnRowCount = true) { return IQueryablePage<TEntity>(pageIndex, pagesize, out rowcount, predicate, orderBy, returnRowCount).Select(selectorResult).ToList(); } public List<TEntity> QueryByPage(int pageIndex, int pagesize, out int rowcount, Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, Dictionary<object, QueryOrderBy>>> orderBy, bool returnRowCount = true) { return IQueryablePage<TEntity>(pageIndex, pagesize, out rowcount, predicate, orderBy).ToList(); } public virtual List<TResult> QueryByPage<TResult>(int pageIndex, int pagesize, Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, Dictionary<object, QueryOrderBy>>> orderBy, Expression<Func<TEntity, TResult>> selectorResult = null) { return IQueryablePage<TEntity>(pageIndex, pagesize, out int rowcount, predicate, orderBy).Select(selectorResult).ToList(); } /// <summary> /// æ›´æ–°è¡¨æ•°æ® /// </summary> /// <param name="entity"></param> /// <param name="saveChanges">是å¦ä¿å˜</param> /// <param name="properties">æ ¼å¼ Expression<Func<entityt, object>> expTree = x => new { x.å—æ®µ1, x.å—æ®µ2 };</param> public virtual int Update(TEntity entity, Expression<Func<TEntity, object>> properties, bool saveChanges = false) { return Update<TEntity>(entity, properties, saveChanges); } public virtual int Update<TSource>(TSource entity, Expression<Func<TSource, object>> properties, bool saveChanges = false) where TSource : class { return UpdateRange(new List<TSource> { entity }, properties, saveChanges); } public virtual int Update<TSource>(TSource entity, string[] properties, bool saveChanges = false) where TSource : class { return UpdateRange<TSource>(new List<TSource>() { entity }, properties, saveChanges); } public virtual int Update<TSource>(TSource entity, bool saveChanges = false) where TSource : class { return UpdateRange<TSource>(new List<TSource>() { entity }, new string[0], saveChanges); } public virtual int UpdateRange<TSource>(IEnumerable<TSource> entities, Expression<Func<TSource, object>> properties, bool saveChanges = false) where TSource : class { return UpdateRange<TSource>(entities, properties?.GetExpressionProperty(), saveChanges); } public virtual int UpdateRange<TSource>(IEnumerable<TSource> entities, bool saveChanges = false) where TSource : class { return UpdateRange<TSource>(entities, new string[0], saveChanges); } /// <summary> /// æ›´æ–°è¡¨æ•°æ® /// </summary> /// <param name="models"></param> /// <param name="properties">æ ¼å¼ Expression<Func<entityt, object>> expTree = x => new { x.å—æ®µ1, x.å—æ®µ2 };</param> public int UpdateRange<TSource>(IEnumerable<TSource> entities, string[] properties, bool saveChanges = false) where TSource : class { if (properties != null && properties.Length > 0) { PropertyInfo[] entityProperty = typeof(TSource).GetProperties(); 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<TSource>(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(); } } /// <summary> /// /// </summary> /// <param name="entity"></param> /// <param name="updateDetail">是å¦ä¿®æ”¹æ˜Žç»†</param> /// <param name="delNotExist">是å¦åˆ 除明细ä¸å˜åœ¨çš„æ•°æ®</param> /// <param name="updateMainFields">ä¸»è¡¨æŒ‡å®šä¿®æ”¹å—æ®µ</param> /// <param name="updateDetailFields">æ˜Žç»†æŒ‡å®šä¿®æ”¹å—æ®µ</param> /// <param name="saveChange">是å¦ä¿å˜</param> /// <returns></returns> public virtual WebResponseContent UpdateRange<Detail>(TEntity entity, bool updateDetail = false, bool delNotExist = false, Expression<Func<TEntity, object>> updateMainFields = null, Expression<Func<Detail, object>> updateDetailFields = null, bool saveChange = false) where Detail : class { WebResponseContent webResponse = new WebResponseContent(); Update(entity, updateMainFields); string message = ""; if (updateDetail) { string detailTypeName = typeof(List<Detail>).FullName; PropertyInfo[] properties = typeof(TEntity).GetProperties(); PropertyInfo detail = properties.Where(x => x.PropertyType.FullName == detailTypeName).ToList().FirstOrDefault(); if (detail != null) { PropertyInfo key = properties.GetKeyProperty(); object obj = detail.GetValue(entity); Type detailType = typeof(TEntity).GetCustomAttribute<EntityAttribute>().DetailTable[0]; message = UpdateDetail<Detail>(obj as List<Detail>, key.Name, key.GetValue(entity), updateDetailFields, delNotExist); } } if (!saveChange) return webResponse.OK(); DbContext.SaveChanges(); return webResponse.OK("修改æˆåŠŸ,明细" + message, entity); } private string UpdateDetail<TDetail>(List<TDetail> list, string keyName, object keyValue, Expression<Func<TDetail, object>> updateDetailFields = null, bool delNotExist = false) where TDetail : class { if (list == null) return ""; PropertyInfo property = typeof(TDetail).GetKeyProperty(); string detailKeyName = property.Name; DbSet<TDetail> details = DbContext.Set<TDetail>(); Expression<Func<TDetail, object>> selectExpression = detailKeyName.GetExpression<TDetail, object>(); Expression<Func<TDetail, bool>> whereExpression = keyName.CreateExpression<TDetail>(keyValue, LinqExpressionType.Equal); List<object> 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<object> keys = new List<object>(); list.ForEach(x => { var set = DbContext.Set<TDetail>(); 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<TDetail>(x, updateDetailFields); // repository.DbContext.Entry<TDetail>(x).State = EntityState.Modified; editCount++; } }); //åˆ é™¤ if (delNotExist) { detailKeys.Where(x => !keys.Contains(x)).ToList().ForEach(d => { delCount++; TDetail detail = Activator.CreateInstance<TDetail>(); property.SetValue(detail, d); DbContext.Entry<TDetail>(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(); } } /// <summary> /// 通过主键批é‡åˆ 除 /// </summary> /// <param name="keys">主键key</param> /// <param name="delList">是å¦è¿žæ˜Žç»†ä¸€èµ·åˆ 除</param> /// <returns></returns> public virtual int DeleteWithKeys(object[] keys, bool delList = false) { Type entityType = typeof(TEntity); string tKey = entityType.GetKeyProperty().Name; FieldType fieldType = entityType.GetFieldType(); string joinKeys = (fieldType == FieldType.Int || fieldType == FieldType.BigInt) ? string.Join(",", keys) : $"'{string.Join("','", keys)}'"; string sql = $"DELETE FROM {entityType.GetEntityTableName()} where {tKey} in ({joinKeys});"; if (delList) { Type detailType = entityType.GetCustomAttribute<EntityAttribute>().DetailTable?[0]; if (detailType != null) sql = sql + $"DELETE FROM {detailType.GetEntityTableName()} where {tKey} in ({joinKeys});"; } return ExecuteSqlCommand(sql); } public virtual Task AddAsync(TEntity entities) { return DBSet.AddRangeAsync(entities); } public virtual Task AddRangeAsync(IEnumerable<TEntity> entities) { return DBSet.AddRangeAsync(entities); } public virtual void Add(TEntity entities, bool saveChanges = false) { AddRange(new List<TEntity>() { entities }, saveChanges); } public virtual void AddRange(IEnumerable<TEntity> entities, bool saveChanges = false) { DBSet.AddRange(entities); if (saveChanges) DbContext.SaveChanges(); } public virtual void AddRange<T>(IEnumerable<T> entities, bool saveChanges = false) where T : class { DbContext.Set<T>().AddRange(entities); if (saveChanges) DbContext.SaveChanges(); } /// <summary> /// 注æ„List生æˆçš„table的列顺åºå¿…é¡»è¦å’Œæ•°æ®åº“表的列顺åºä¸€è‡´ /// </summary> /// <typeparam name="T"></typeparam> /// <param name="entities"></param> public virtual void BulkInsert(IEnumerable<TEntity> entities, bool setOutputIdentity = false) { // EFContext.Model.FindEntityType("").Relational() //Pomelo.EntityFrameworkCore.MySql try { // EFContext.BulkInsert(entities.ToList()); } catch (DbUpdateException ex) { throw (ex.InnerException as Exception ?? ex); } // BulkInsert(entities.ToDataTable(), typeof(T).GetEntityTableName(), null); } public virtual int SaveChanges() { return EFContext.SaveChanges(); } public virtual Task<int> SaveChangesAsync() { return EFContext.SaveChangesAsync(); } public virtual int ExecuteSqlCommand(string sql, params SqlParameter[] sqlParameters) { return DbContext.Database.ExecuteSqlRaw(sql, sqlParameters); } public virtual List<TEntity> FromSql(string sql, params SqlParameter[] sqlParameters) { return DBSet.FromSqlRaw(sql, sqlParameters).ToList(); } /// <summary> /// 执行sql /// ä½¿ç”¨æ–¹å¼ FormattableString sql=$"select * from xx where name ={xx} and pwd={xx1} ", /// FromSqlInterpolated内部处ç†sql注入的问题,直接在{xx}写对应的值å³å¯ /// 注æ„:sqlå¿…é¡» select * 返回所有TEntityå—æ®µï¼Œ /// </summary> /// <param name="formattableString"></param> /// <returns></returns> public virtual IQueryable<TEntity> FromSqlInterpolated([NotNull] FormattableString sql) { //DBSet.FromSqlInterpolated(sql).Select(x => new { x,xxx}).ToList(); return DBSet.FromSqlInterpolated(sql); } /// <summary> /// å–æ¶ˆä¸Šä¸‹æ–‡è·Ÿè¸ª /// </summary> /// <param name="entity"></param> public virtual void Detached(TEntity entity) { DbContext.Entry(entity).State = EntityState.Detached; } public virtual void DetachedRange(IEnumerable<TEntity> entities) { foreach (var entity in entities) { DbContext.Entry(entity).State = EntityState.Detached; } } /// <summary> /// æŸ¥è¯¢å—æ®µä¸ä¸ºnull或者为空 /// </summary> /// <param name="field">x=>new {x.å—æ®µ}</param> /// <param name="value">查询的类</param> /// <param name="linqExpression">查询类型</param> /// <returns></returns> public virtual IQueryable<TEntity> WhereIF([NotNull] Expression<Func<TEntity, object>> field, string value, LinqExpressionType linqExpression = LinqExpressionType.Equal) { return EFContext.Set<TEntity>().WhereNotEmpty(field, value, linqExpression); } public virtual IQueryable<TEntity> WhereIF(bool checkCondition, Expression<Func<TEntity, bool>> predicate) { if (checkCondition) { return EFContext.Set<TEntity>().Where(predicate); } return EFContext.Set<TEntity>(); } public virtual IQueryable<T> WhereIF<T>(bool checkCondition, Expression<Func<T, bool>> predicate) where T : class { if (checkCondition) { return EFContext.Set<T>().Where(predicate); } return EFContext.Set<T>(); } } }