1656 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			1656 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			C#
		
	
	
| using System;
 | ||
| using System.Collections.Generic;
 | ||
| using System.ComponentModel.DataAnnotations;
 | ||
| using System.Linq;
 | ||
| using System.Linq.Expressions;
 | ||
| using System.Reflection;
 | ||
| using System.Threading;
 | ||
| using System.Threading.Tasks;
 | ||
| using AutoMapper;
 | ||
| using IRaCIS.Core.Domain.Models;
 | ||
| using Microsoft.EntityFrameworkCore;
 | ||
| using Microsoft.EntityFrameworkCore.ChangeTracking;
 | ||
| using AutoMapper.QueryableExtensions;
 | ||
| using EFCore.BulkExtensions;
 | ||
| using IRaCIS.Core.Domain.Share;
 | ||
| using IRaCIS.Core.Infrastructure;
 | ||
| using IRaCIS.Core.Infrastructure.Extention;
 | ||
| using Microsoft.Data.SqlClient;
 | ||
| using Newtonsoft.Json;
 | ||
| using Newtonsoft.Json.Linq;
 | ||
| using IRaCIS.Core.Domain.Common;
 | ||
| using IRaCIS.Core.Infra.EFCore.Common.Dto;
 | ||
| 
 | ||
| namespace IRaCIS.Core.Infra.EFCore
 | ||
| {
 | ||
|     public class Repository<TEntity> : IRepository<TEntity>
 | ||
|         where TEntity : Entity, new()
 | ||
|     {
 | ||
| 
 | ||
|         public IMapper _mapper { get; set; }
 | ||
|         public IRaCISDBContext _dbContext { get; set; }
 | ||
| 
 | ||
|         public DbSet<TEntity> _dbSet => _dbContext.Set<TEntity>();
 | ||
| 
 | ||
|         public IUserInfo _userInfo { get; set; }
 | ||
| 
 | ||
|         public Repository(IRaCISDBContext dbContext, IMapper mapper, IUserInfo userInfo)
 | ||
|         {
 | ||
|             _dbContext = dbContext;
 | ||
|             _mapper = mapper;
 | ||
|             _userInfo = userInfo;
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         #region 异步 EF 跟踪 添加
 | ||
|         public async Task<IEnumerable<TEntity>> AddRangeAsync(IEnumerable<TEntity> entities, bool isSaveAudit = false)
 | ||
|         {
 | ||
|             foreach (var addEntity in entities)
 | ||
|             {
 | ||
|                 await AddAsync(addEntity, isSaveAudit);
 | ||
|             }
 | ||
| 
 | ||
|             return entities;
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>EF跟踪方式 添加</summary>
 | ||
|         public async ValueTask<TEntity> AddAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default, bool isSaveAudit = false)
 | ||
|         {
 | ||
| 
 | ||
|             await _dbSet.AddAsync(entity).ConfigureAwait(false);
 | ||
| 
 | ||
|             // 添加稽查
 | ||
|             //await AddInspectionAsync(entity, isSaveAudit);
 | ||
| 
 | ||
|             if (autoSave)
 | ||
|             {
 | ||
|                 await SaveChangesAsync(cancellationToken);
 | ||
|             }
 | ||
| 
 | ||
|             return entity;
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         public async Task<TEntity> InsertFromDTOAsync<TFrom>(TFrom from, bool autoSave = false, params EntityVerifyExp<TEntity>[] verify)
 | ||
|         {
 | ||
|             var entity = _mapper.Map<TEntity>(from);
 | ||
| 
 | ||
|             await EntityVerifyAsync(true, verify);
 | ||
| 
 | ||
| 
 | ||
|             entity = await AddAsync(entity, autoSave);
 | ||
| 
 | ||
| 
 | ||
|             return entity;
 | ||
| 
 | ||
|         }
 | ||
|         #endregion
 | ||
| 
 | ||
| 
 | ||
|         #region 异步 EF 跟踪  部分字段更新
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>用前端传递的视图模型字段,更新,同时返回数据库该条记录的原始信息,方便对比某些字段是否更改,进行相应的逻辑操作</summary>
 | ||
| 
 | ||
|         public async Task<TEntity> UpdateFromDTOAsync<TFrom>(TFrom from, bool autoSave = false, bool ignoreDtoNullProperty = true, params EntityVerifyExp<TEntity>[] verify)
 | ||
|         {
 | ||
| 
 | ||
|             var entity = _mapper.Map<TEntity>(from);
 | ||
| 
 | ||
|             await EntityVerifyAsync(false, verify, entity.Id);
 | ||
| 
 | ||
|             var dbEntity = await _dbSet.IgnoreQueryFilters().FirstOrDefaultAsync(t => t.Id == entity.Id).ConfigureAwait(false);
 | ||
| 
 | ||
|             if (dbEntity == null)
 | ||
|             {
 | ||
|                 throw new BusinessValidationFailedException(
 | ||
|                     " Update object not exist in db,Please check if the parameter Id is passed incorrectly");
 | ||
|             }
 | ||
| 
 | ||
|             var dbBeforEntity = dbEntity.Clone();
 | ||
| 
 | ||
| 
 | ||
|             _mapper.Map(from, dbEntity);
 | ||
| 
 | ||
| 
 | ||
|             //DTO  null  属性不更新  防止意外操作,导致保存数据错误,或者 add 和update 用一个模型,更新的时候,只传递了部分字段,导致,不想更新的字段,因为没传递值,用null覆盖了
 | ||
|             // Guid?属性 为null 时   映射到  Guid 时  默认会变成  Guid.Empty   
 | ||
|             if (ignoreDtoNullProperty)
 | ||
|             {
 | ||
|                 var dbEntityProp = typeof(TEntity).GetProperties();
 | ||
|                 foreach (var propertyInfo in from.GetType().GetProperties())
 | ||
|                 {
 | ||
|                     if (propertyInfo.GetValue(from) == null && dbEntityProp.Any(t => t.Name == propertyInfo.Name))
 | ||
|                     {
 | ||
|                         _dbContext.Entry(dbEntity).Property(propertyInfo.Name).IsModified = false;
 | ||
|                     }
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|             await SaveChangesAsync(autoSave);
 | ||
| 
 | ||
| 
 | ||
|             return dbBeforEntity;
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         /// <summary> EF跟踪方式  生成 部分字段更新, 通过主键id  和表达式树 更新部分字段
 | ||
|         /// 例如  Guid.Parse("8a90c96e-0776-4f7b-82a6-18933d339584"),u => new Dictionary() { ParentId = null, Code = "test" }默认会去处理更新更新人 更新时间</summary>
 | ||
| 
 | ||
|         public async Task UpdatePartialNoQueryAsync(Guid id, Expression<Func<TEntity, TEntity>> updateFactory, bool autoSave = false, params EntityVerifyExp<TEntity>[] verify)
 | ||
|         {
 | ||
|             await SetPartialFieldUpdateAsync(id, updateFactory, verify);
 | ||
| 
 | ||
|             await SaveChangesAsync(autoSave);
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary> EF跟踪方式  生成 部分字段立即更新,默认会去处理更新更新人 更新时间  </summary>
 | ||
|         public async Task<bool> UpdatePartialNowNoQueryAsync(Guid id, Expression<Func<TEntity, TEntity>> updateFactory,
 | ||
|             params EntityVerifyExp<TEntity>[] verify)
 | ||
|         {
 | ||
|             await SetPartialFieldUpdateAsync(id, updateFactory, verify);
 | ||
|             return await SaveChangesAsync(true);
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>注意 模型标注了 ConcurrencyCheck的属性,这样的实体,不适合用部分字段更新,ef生成的更新sql会自动带上ConcurrencyCheck的属性条件</summary>
 | ||
|         private async Task SetPartialFieldUpdateAsync(Guid id, Expression<Func<TEntity, TEntity>> updateFactory, params EntityVerifyExp<TEntity>[] verify)
 | ||
|         {
 | ||
|             await EntityVerifyAsync(false, verify, id);
 | ||
| 
 | ||
|             var entity = new TEntity() { Id = id };
 | ||
| 
 | ||
|             var entityEntry = _dbContext.Entry(entity);
 | ||
| 
 | ||
|             entityEntry.State = EntityState.Detached;
 | ||
| 
 | ||
| 
 | ||
|             List<PropertyInfo> list = ((MemberInitExpression)updateFactory.Body).Bindings.Select(mb => mb.Member.Name)
 | ||
|                 .Select(propName => typeof(TEntity).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)).ToList();
 | ||
| 
 | ||
|             Func<TEntity, TEntity> func = updateFactory.Compile();
 | ||
| 
 | ||
|             TEntity applyObj = func(entity);
 | ||
| 
 | ||
|             foreach (PropertyInfo prop in list)
 | ||
|             {
 | ||
|                 object value = prop.GetValue((object)applyObj);
 | ||
|                 prop.SetValue((object)entity, value);
 | ||
| 
 | ||
|                 _dbContext.Entry(entity).Property(prop.Name).IsModified = true;
 | ||
|             }
 | ||
| 
 | ||
|             #region Test
 | ||
| 
 | ||
| 
 | ||
|             //updateFactory.Compile()(entity);
 | ||
| 
 | ||
|             //List<string> propNameList = ((MemberInitExpression)updateFactory.Body).Bindings.Select(mb => mb.Member.Name).ToList();
 | ||
| 
 | ||
|             //foreach (string propName in propNameList)
 | ||
|             //{
 | ||
|             //    _dbContext.Entry(entity).Property(propName).IsModified = true;
 | ||
|             //}
 | ||
| 
 | ||
|             #endregion
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         #endregion
 | ||
| 
 | ||
| 
 | ||
|         #region 异步  EF 跟踪 自动生成 更新 和删除语句
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>EF跟踪方式 更新,全字段更新  不好</summary>
 | ||
|         public async Task<bool> UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
 | ||
|         {
 | ||
|             _dbSet.Update(entity);
 | ||
| 
 | ||
|             if (autoSave)
 | ||
|             {
 | ||
|                 return await SaveChangesAsync(cancellationToken);
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 return false;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>EF跟踪方式  外层先有查询好的完成实体,再更新部分字段  稽查的时候需要完整的实体信息</summary>
 | ||
|         public async Task<bool> UpdateAsync(TEntity waitModifyEntity, Expression<Func<TEntity, TEntity>> updateFactory, bool autoSave = false, CancellationToken cancellationToken = default)
 | ||
|         {
 | ||
|             var entityEntry = _dbContext.Entry(waitModifyEntity);
 | ||
|             entityEntry.State = EntityState.Detached;
 | ||
| 
 | ||
| 
 | ||
|             ModifyPartialFiled(waitModifyEntity, updateFactory);
 | ||
| 
 | ||
|             return await SaveChangesAsync(autoSave);
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>EF跟踪方式  先查询出来,再更新部分字段 稽查的时候需要完整的实体信息</summary>
 | ||
|         public async Task<TEntity> UpdatePartialFromQueryAsync(Guid id, Expression<Func<TEntity, TEntity>> updateFactory,
 | ||
|             bool autoSave = false, bool ignoreQueryFilter = false, CancellationToken cancellationToken = default)
 | ||
|         {
 | ||
| 
 | ||
|             var query = ignoreQueryFilter ? _dbSet.AsNoTracking().IgnoreQueryFilters() : _dbSet.AsNoTracking();
 | ||
|             //不跟踪 查询出来的实体就是Detached
 | ||
|             var searchEntity = await query.IgnoreQueryFilters().FirstOrDefaultAsync(t => t.Id == id);
 | ||
| 
 | ||
|             if (searchEntity == null)
 | ||
|             {
 | ||
|                 throw new BusinessValidationFailedException(
 | ||
|                     " Update object not exist in db,Please check if the parameter Id is passed incorrectly");
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|             ModifyPartialFiled(searchEntity, updateFactory);
 | ||
| 
 | ||
| 
 | ||
|             await SaveChangesAsync(autoSave);
 | ||
| 
 | ||
|             return searchEntity;
 | ||
|         }
 | ||
| 
 | ||
|         public async Task UpdatePartialFromQueryAsync(Expression<Func<TEntity, bool>> updateFilter,
 | ||
|             Expression<Func<TEntity, TEntity>> updateFactory,
 | ||
|             bool autoSave = false, bool ignoreQueryFilter = false, CancellationToken cancellationToken = default)
 | ||
|         {
 | ||
|             if (updateFilter == null)
 | ||
|             {
 | ||
|                 throw new ArgumentException("更新过滤条件不允许为空", nameof(updateFilter));
 | ||
|             }
 | ||
|             var query = ignoreQueryFilter ? _dbSet.AsNoTracking().IgnoreQueryFilters() : _dbSet.AsNoTracking();
 | ||
| 
 | ||
|             var searchEntityList = await query.Where(updateFilter).ToListAsync();
 | ||
| 
 | ||
|             foreach (var needUpdateEntity in searchEntityList)
 | ||
|             {
 | ||
|                 await UpdateAsync(needUpdateEntity, updateFactory, autoSave);
 | ||
|             }
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>更新后拥有完整的实体信息,便于稽查</summary>
 | ||
|         private void ModifyPartialFiled(TEntity waitModifyEntity, Expression<Func<TEntity, TEntity>> updateFactory)
 | ||
|         {
 | ||
|             List<PropertyInfo> list = ((MemberInitExpression)updateFactory.Body).Bindings.Select(mb => mb.Member.Name)
 | ||
|                 .Select(propName => typeof(TEntity).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)).ToList();
 | ||
| 
 | ||
|             Func<TEntity, TEntity> func = updateFactory.Compile();
 | ||
| 
 | ||
|             TEntity applyObj = func(waitModifyEntity);
 | ||
| 
 | ||
|             //深拷贝更新之前实体信息
 | ||
|             //var copyObj = waitModifyEntity.Clone();
 | ||
| 
 | ||
|             foreach (PropertyInfo prop in list)
 | ||
|             {
 | ||
|                 object value = prop.GetValue(applyObj);
 | ||
|                 prop.SetValue(waitModifyEntity, value);
 | ||
| 
 | ||
|                 _dbContext.Entry(waitModifyEntity).Property(prop.Name).IsModified = true;
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>EF跟踪方式 删除</summary>
 | ||
|         public async Task<bool> DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
 | ||
|         {
 | ||
|             _dbSet.Remove(entity);
 | ||
| 
 | ||
|             return await SaveChangesAsync(autoSave);
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>EF跟踪方式(查询出来,再删除 浪费性能,但是稽查 或者触发某些操作时,需要知道数据库实体信息 不可避免用这种)</summary>
 | ||
|         public async Task<TEntity> DeleteFromQueryAsync(Guid id, bool autoSave = false, bool ignoreQueryFilter = false)
 | ||
|         {
 | ||
|             var query = ignoreQueryFilter ? _dbSet.AsNoTracking().IgnoreQueryFilters() : _dbSet.AsNoTracking();
 | ||
| 
 | ||
|             var waitDelete = await query.Where(t => t.Id == id).FirstOrDefaultAsync();
 | ||
| 
 | ||
|             if (waitDelete == null)
 | ||
|             {
 | ||
|                 throw new BusinessValidationFailedException(
 | ||
|                     " Delete object not exist in db,Please check if the parameter Id is passed incorrectly");
 | ||
|             }
 | ||
| 
 | ||
|             await DeleteAsync(waitDelete, autoSave);
 | ||
| 
 | ||
|             return waitDelete;
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>批量删除,EF跟踪方式(所有查询出来,再删除 浪费性能,但是稽查 或者触发某些操作时,需要知道数据库实体信息 不可避免用这种)</summary>
 | ||
|         public async Task<List<TEntity>> DeleteFromQueryAsync(Expression<Func<TEntity, bool>> deleteFilter, bool autoSave = false, bool ignoreQueryFilter = false)
 | ||
|         {
 | ||
|             var query = ignoreQueryFilter ? _dbSet.AsNoTracking().IgnoreQueryFilters() : _dbSet.AsNoTracking();
 | ||
|             var waitDeleteList = await query.Where(deleteFilter).ToListAsync();
 | ||
| 
 | ||
|             foreach (var deleteItem in waitDeleteList)
 | ||
|             {
 | ||
|                 await DeleteAsync(deleteItem, false);
 | ||
|             }
 | ||
| 
 | ||
|             await SaveChangesAsync(autoSave);
 | ||
| 
 | ||
|             return waitDeleteList;
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
|         public async Task<List<TEntity>> SoftDeleteFromQueryAsync(Expression<Func<TEntity, bool>> deleteFilter, bool autoSave = false, bool ignoreQueryFilter = false)
 | ||
|         {
 | ||
|             var query = ignoreQueryFilter ? _dbSet.IgnoreQueryFilters() : _dbSet;
 | ||
|             var waitDeleteList =  await query.Where(deleteFilter).ToListAsync();
 | ||
|      
 | ||
|             foreach (var deleteItem in waitDeleteList)
 | ||
|             {
 | ||
|                 if(deleteItem is ISoftDelete softDeleteItem)
 | ||
|                 {
 | ||
|                     softDeleteItem.IsDeleted = true;
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|             await SaveChangesAsync(autoSave);
 | ||
| 
 | ||
|             return waitDeleteList;
 | ||
|         }
 | ||
| 
 | ||
|         #endregion
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         #region 不走EF 跟踪机制的删除 更新  以及批量操作
 | ||
| 
 | ||
|         /// <summary>批量删除,相当于原生sql,  没用EF跟踪方式(所有查询出来,再删除 浪费性能)</summary>
 | ||
|         public async Task<bool> BatchDeleteNoTrackingAsync(Expression<Func<TEntity, bool>> deleteFilter)
 | ||
|         {
 | ||
|             return await _dbSet.IgnoreQueryFilters().Where(deleteFilter).BatchDeleteAsync() > 0;
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>批量更新,相当于原生sql,  没用EF跟踪方式(所有查询出来,再更新 浪费性能)</summary>
 | ||
|         public async Task<bool> BatchUpdateNoTrackingAsync(Expression<Func<TEntity, bool>> where,
 | ||
|             Expression<Func<TEntity, TEntity>> updateFactory)
 | ||
|         {
 | ||
| 
 | ||
|             var bindings = ((MemberInitExpression)updateFactory.Body).Bindings.ToList();
 | ||
| 
 | ||
|             var hasPropNameList = bindings.Select(t => t.Member.Name).ToList();
 | ||
| 
 | ||
| 
 | ||
|             if (typeof(IAuditUpdate).IsAssignableFrom(typeof(TEntity)))
 | ||
|             {
 | ||
| 
 | ||
|                 if (!hasPropNameList.Contains(nameof(IAuditUpdate.UpdateTime)))
 | ||
|                 {
 | ||
|                     bindings.Add(Expression.Bind(typeof(TEntity).GetMember(nameof(IAuditUpdate.UpdateTime))[0], Expression.Constant(DateTime.Now)));
 | ||
| 
 | ||
|                 }
 | ||
| 
 | ||
|                 if (!hasPropNameList.Contains(nameof(IAuditUpdate.UpdateUserId)))
 | ||
|                 {
 | ||
|                     bindings.Add(Expression.Bind(typeof(TEntity).GetMember(nameof(IAuditUpdate.UpdateUserId))[0], Expression.Constant(_userInfo.Id)));
 | ||
| 
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|             var member = Expression.MemberInit(Expression.New(typeof(TEntity)), bindings);
 | ||
| 
 | ||
|             var factory = Expression.Lambda<Func<TEntity, TEntity>>(member, Expression.Parameter(typeof(TEntity), "x"));
 | ||
| 
 | ||
| 
 | ||
|             return await _dbSet.IgnoreQueryFilters().Where(where).BatchUpdateAsync(factory) > 0;
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
|         #endregion
 | ||
| 
 | ||
| 
 | ||
|         #region 保存 、忽略 、验证
 | ||
|         public async Task<TEntity> InsertOrUpdateAsync<TFrom>(TFrom from, bool autoSave = false, params EntityVerifyExp<TEntity>[] verify)
 | ||
|         {
 | ||
|             var entity = _mapper.Map<TEntity>(from);
 | ||
| 
 | ||
| 
 | ||
|             if (entity.Id == Guid.Empty)
 | ||
|             {
 | ||
|                 return await InsertFromDTOAsync(from, autoSave, verify);
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 return await UpdateFromDTOAsync(from, autoSave, false, verify);
 | ||
|             }
 | ||
|         }
 | ||
|         private async Task EntityVerifyAsync(bool isAdd, EntityVerifyExp<TEntity>[] verify, Guid? entitydId = null)
 | ||
|         {
 | ||
| 
 | ||
|             if (isAdd)
 | ||
|             {
 | ||
|                 foreach (var verifyItem in verify.Where(t => t.verifyType != VerifyEnum.OnlyUpdate && t.IsVerify))
 | ||
|                 {
 | ||
|                     if (await _dbSet.AnyAsync(verifyItem.VerifyExp).ConfigureAwait(false))
 | ||
|                     {
 | ||
|                         throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
 | ||
|                     }
 | ||
|                 }
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 foreach (var verifyItem in verify.Where(t => t.verifyType != VerifyEnum.OnlyAdd && t.IsVerify))
 | ||
|                 {
 | ||
|                     if (verifyItem.verifyType == VerifyEnum.OnlyUpdate)
 | ||
|                     {
 | ||
|                         if (await _dbSet.AnyAsync(verifyItem.VerifyExp).ConfigureAwait(false))
 | ||
|                         {
 | ||
|                             throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
 | ||
|                         }
 | ||
|                     }
 | ||
|                     else if (verifyItem.verifyType == VerifyEnum.Both)
 | ||
|                     {
 | ||
|                         if (await _dbSet.AnyAsync(verifyItem.VerifyExp.And(t => t.Id != entitydId)).ConfigureAwait(false))
 | ||
|                         {
 | ||
|                             throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
 | ||
|                         }
 | ||
|                     }
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
|         private async Task<bool> SaveChangesAsync(bool autoSave)
 | ||
|         {
 | ||
|             if (autoSave)
 | ||
|             {
 | ||
|                 return await SaveChangesAsync();
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 return false;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 忽略空值属性
 | ||
|         /// </summary>
 | ||
|         /// <param name="entity"></param>
 | ||
|         /// <param name="ignoreNullValues"></param>
 | ||
|         private void IgnoreNullValues(ref TEntity entity, bool? ignoreNullValues = null)
 | ||
|         {
 | ||
|             var isIgnore = ignoreNullValues;
 | ||
|             if (isIgnore == false) return;
 | ||
| 
 | ||
|             // 获取所有的属性
 | ||
|             var properties = _dbSet.EntityType.GetProperties();
 | ||
|             if (properties == null) return;
 | ||
| 
 | ||
|             foreach (var propety in properties)
 | ||
|             {
 | ||
|                 var entityProperty = _dbContext.Entry(entity).Property(propety.Name);
 | ||
|                 var propertyValue = entityProperty?.CurrentValue;
 | ||
|                 var propertyType = entityProperty?.Metadata?.PropertyInfo?.PropertyType;
 | ||
| 
 | ||
|                 // 判断是否是无效的值,比如为 null,默认时间,以及空 Guid 值
 | ||
|                 var isInvalid = propertyValue == null
 | ||
|                                 || (propertyType == typeof(DateTime) && propertyValue?.ToString() == new DateTime().ToString())
 | ||
|                                 || (propertyType == typeof(DateTimeOffset) && propertyValue?.ToString() == new DateTimeOffset().ToString())
 | ||
|                                 || (propertyType == typeof(Guid) && propertyValue?.ToString() == Guid.Empty.ToString());
 | ||
| 
 | ||
|                 if (isInvalid && entityProperty != null)
 | ||
|                 {
 | ||
|                     entityProperty.IsModified = false;
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         public async Task<bool> SaveChangesAsync(CancellationToken cancellationToken = default)
 | ||
|         {
 | ||
|             return await _dbContext.SaveChangesAsync(cancellationToken) > 0;
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         #endregion
 | ||
| 
 | ||
|         #region 不常用
 | ||
|         /// <summary>EF跟踪方式  生成 部分字段更新  (只更新传递的字段名 new[] {nameof(User.Name), nameof(User.Age))</summary>
 | ||
|         public async Task<TEntity> UpdatePartialFieldsAsync(TEntity entity, string[] propertyNames,
 | ||
|             bool autoSave = false, bool ignoreEntityNullProperty = true, params EntityVerifyExp<TEntity>[] verify)
 | ||
|         {
 | ||
|             await EntityVerifyAsync(false, verify, entity.Id);
 | ||
| 
 | ||
|             var entityEntry = _dbContext.Entry(entity);
 | ||
|             entityEntry.State = EntityState.Detached;
 | ||
| 
 | ||
| 
 | ||
|             foreach (var propertyName in propertyNames)
 | ||
|             {
 | ||
|                 _dbContext.Entry(entity).Property(propertyName).IsModified = true;
 | ||
|             }
 | ||
| 
 | ||
|             // 忽略空值
 | ||
|             IgnoreNullValues(ref entity, ignoreEntityNullProperty);
 | ||
| 
 | ||
|             return entityEntry.Entity;
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>更新  排除某些字段的更新  排除方式: new[] {nameof(User.Name), nameof(User.Age)</summary>
 | ||
|         public async Task<TEntity> UpdateExcludeFields(TEntity entity, string[] propertyNames, bool autoSave = false, bool ignoreEntityNullProperty = true, params EntityVerifyExp<TEntity>[] verify)
 | ||
|         {
 | ||
| 
 | ||
|             await EntityVerifyAsync(false, verify, entity.Id);
 | ||
| 
 | ||
|             var entityEntry = _dbContext.Entry(entity);
 | ||
|             entityEntry.State = EntityState.Modified;
 | ||
| 
 | ||
| 
 | ||
|             foreach (var propertyName in propertyNames)
 | ||
|             {
 | ||
|                 _dbContext.Entry(entity).Property(propertyName).IsModified = false;
 | ||
|             }
 | ||
| 
 | ||
|             // 忽略空值
 | ||
|             IgnoreNullValues(ref entity, ignoreEntityNullProperty);
 | ||
| 
 | ||
|             return entityEntry.Entity;
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         #endregion
 | ||
| 
 | ||
|         #region 稽查
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 翻译稽查数据
 | ||
|         /// </summary>
 | ||
|         /// <param name="dto">传入Dto</param>
 | ||
|         /// <returns></returns>
 | ||
|         public async Task<List<string>> SetInspectionEnumValue(SetInspectionEnumValueDto dto)
 | ||
|         {
 | ||
|             var listIdentification = dto.Items.Select(x => x.Identification).ToList() ;
 | ||
|             foreach (var item in dto.Items)
 | ||
|             {
 | ||
|                 if (item.Identification == string.Empty || item.Json == string.Empty)
 | ||
|                 {
 | ||
|                     continue;
 | ||
|                 }
 | ||
|                 item.Json = await GetInspectionEnumValue(listIdentification, item.Json);
 | ||
|                 item.Json = await SetEnum(dto.TrialId, listIdentification, item.Json);
 | ||
|                 item.Json = await SetDataInspectionDateType(listIdentification, item.Json);
 | ||
|             }
 | ||
|             return dto.Items.Select(x => x.Json).ToList();
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 格式化日期和时间
 | ||
|         /// </summary>
 | ||
|         /// <param name="Data">稽查数据</param>
 | ||
|         /// <returns></returns>
 | ||
|         public async Task<string> SetDataInspectionDateType(List<string> identification, string json)
 | ||
|         {
 | ||
|             var list = await (from parent in _dbContext.FrontAuditConfig.AsQueryable().Where(x => identification.Contains(x.Identification))
 | ||
|                               join child in _dbContext.FrontAuditConfig.AsQueryable().Where(x => x.EnumType == "Date" && x.IsEnable.HasValue && x.IsEnable.Value) on parent.Id equals child.ParentId
 | ||
|                               select new DateDto()
 | ||
|                               {
 | ||
|                                   Code = child.Code,
 | ||
|                                   DateType = child.DateType,
 | ||
|                               }).ToListAsync();
 | ||
| 
 | ||
|             list = list.GroupBy(x => new { x.Code }, (key, lst) => new DateDto()
 | ||
|             {
 | ||
|                 Code = key.Code,
 | ||
|                 DateType = lst.Max(x => x.DateType),
 | ||
|             }).ToList();
 | ||
| 
 | ||
|             var JsonData = JsonConvert.DeserializeObject<IDictionary<string, object>>(json);
 | ||
| 
 | ||
|             if (JsonData == null)
 | ||
|             {
 | ||
|                 return json;
 | ||
|             }
 | ||
| 
 | ||
|             foreach (var item in JsonData.Keys)
 | ||
|             {
 | ||
|                 var datefirst = list.FirstOrDefault(x => x.Code.ToLower() == item.ToLower());
 | ||
|                 if (datefirst != null && !IsNullOrEmpty(JsonData[item]))
 | ||
|                 {
 | ||
|                     try
 | ||
|                     {
 | ||
|                         if (datefirst.DateType == "Date")
 | ||
|                         {
 | ||
|                             JsonData[item] = DateTime.Parse(JsonData[item].ToString()).ToString("yyyy-MM-dd");
 | ||
|                         }
 | ||
| 
 | ||
|                         if (datefirst.DateType == "DateTime")
 | ||
|                         {
 | ||
|                             JsonData[item] = DateTime.Parse(JsonData[item].ToString()).ToString("yyyy-MM-dd HH:mm:ss");
 | ||
|                         }
 | ||
|                     }
 | ||
|                     catch (Exception)
 | ||
|                     {
 | ||
|                         continue;
 | ||
|                     }
 | ||
|                 }
 | ||
| 
 | ||
|             }
 | ||
| 
 | ||
|             return JsonConvert.SerializeObject(JsonData);
 | ||
| 
 | ||
|           
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 获取外键表数据
 | ||
|         /// </summary>
 | ||
|         /// <param name="Table">表名称</param>
 | ||
|         /// <param name="ForeignKeyValue">外键value</param>
 | ||
|         /// <param name="ForeignKeyText">要查询的外键值</param>
 | ||
|         /// <param name="value">传入的纸</param>
 | ||
|         /// <returns></returns>
 | ||
|         public async Task<string> GetInspectionEnumValue(List<string> identification, string json)
 | ||
|         {
 | ||
|             var list = await (from u in _dbContext.FrontAuditConfig.Where(x => identification.Contains(x.Identification))
 | ||
|                               join p in _dbContext.FrontAuditConfig.Where(x => x.EnumType == "Foreign" && x.IsEnable.HasValue && x.IsEnable.Value) on u.Id equals p.ParentId
 | ||
|                               select new
 | ||
|                               {
 | ||
|                                   Key = p.Code,
 | ||
|                                   ForeignKeyValue = p.ForeignKeyValue,
 | ||
|                                   ForeignKeyText = p.ForeignKeyText,
 | ||
|                                   ForeignKeyTable = p.ForeignKeyTable
 | ||
|                               }).ToListAsync();
 | ||
|             
 | ||
|             list= list.GroupBy(x => new { x.Key }, (key, lst) => new 
 | ||
|             {
 | ||
|                 Key=key.Key,
 | ||
|                 ForeignKeyValue=lst.Max(x=>x.ForeignKeyValue),
 | ||
|                 ForeignKeyText = lst.Max(x => x.ForeignKeyText),
 | ||
|                 ForeignKeyTable = lst.Max(x => x.ForeignKeyTable),
 | ||
| 
 | ||
|             }).ToList();
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|             var JsonDataValue = JsonConvert.DeserializeObject<IDictionary<string, object>>(json);
 | ||
|             foreach (var item in list)
 | ||
|             {
 | ||
|                 if (!JsonDataValue.ContainsKey(item.Key))
 | ||
|                 {
 | ||
|                     continue;
 | ||
|                 }
 | ||
|                 string Table = item.ForeignKeyTable;
 | ||
|                 string ForeignKeyValue = item.ForeignKeyValue;
 | ||
|                 string ForeignKeyText = item.ForeignKeyText;
 | ||
|                 if (JsonDataValue[item.Key] != null)
 | ||
|                 {
 | ||
|                     string value = JsonDataValue[item.Key].ToString();
 | ||
|                     string para = string.Empty;
 | ||
|                     string sql = string.Empty;
 | ||
|                     var JsonData = JsonConvert.DeserializeObject<IDictionary<string, object>>(JsonConvert.SerializeObject(new { item = value }));
 | ||
|                     if (JsonData["item"].GetType() == typeof(JArray))
 | ||
|                     {
 | ||
|                         foreach (var v in JsonData["item"] as JArray)
 | ||
|                         {
 | ||
|                             para += para == string.Empty ? $"'{v.ToString()}'" : $",'{v.ToString()}'";
 | ||
|                         }
 | ||
|                         sql = $"select {ForeignKeyText} Text from {Table} where {ForeignKeyValue} in (@para)";
 | ||
|                     }
 | ||
|                     else
 | ||
|                     {
 | ||
|                         para = $"{JsonData["item"].ToString()}";
 | ||
|                         sql = $"select {ForeignKeyText}  Text from {Table} where {ForeignKeyValue} = @para";
 | ||
|                     }
 | ||
|                     SqlParameter[] paravalue = new SqlParameter[] {
 | ||
|                    new SqlParameter("@para",para)
 | ||
|                                              };
 | ||
|                     JsonDataValue[item.Key] = string.Join(",", _dbContext.Database.SqlQuery<ForeignKey>(sql, paravalue).Select(x => x.Text).ToList());
 | ||
|                 }
 | ||
|                
 | ||
|             }
 | ||
|             return JsonConvert.SerializeObject(JsonDataValue);
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 获取枚举
 | ||
|         /// </summary>
 | ||
|         /// <param name="Identification">标识</param>
 | ||
|         /// <param name="json">Json对象</param>
 | ||
|         /// <returns></returns>
 | ||
|         /// <exception cref="BusinessValidationFailedException"></exception>
 | ||
|         public async Task<string> SetEnum(Guid trilaid, List<string> identification, string json)
 | ||
|         {
 | ||
|             if (json == null||json=="null")
 | ||
|             {
 | ||
|                 return null;
 | ||
|             }
 | ||
|             var list = await (from u in _dbContext.FrontAuditConfig.Where(x => identification.Contains(x.Identification))
 | ||
|                               join p in _dbContext.FrontAuditConfig.Where(x => x.Code != "AuditState" && x.EnumType == "Dictionary"&&x.IsEnable.HasValue&& x.IsEnable.Value) on u.Id equals p.ParentId
 | ||
|                               select new
 | ||
|                               {
 | ||
|                                   Key = p.Code,
 | ||
|                                   Code = p.DictionaryCode,
 | ||
|                                   Type = p.DictionaryType
 | ||
|                               }).ToListAsync();
 | ||
| 
 | ||
|             // 添加单双审
 | ||
|             var trialtype = await _dbContext.Trial.AsQueryable().Where(x => x.Id == trilaid).Select(x => x.QCProcessEnum).FirstOrDefaultAsync();
 | ||
| 
 | ||
|             list.Add(new
 | ||
|             {
 | ||
| 
 | ||
|                 Key = "AuditState",
 | ||
|                 Code = trialtype == TrialQCProcess.SingleAudit ? "AuditStatePE" : "AuditStateRC",
 | ||
|                 Type = "Code",
 | ||
|             });
 | ||
| 
 | ||
| 
 | ||
|             list = list.GroupBy(x => new { x.Key }, (key, lst) => new
 | ||
|             {
 | ||
|                 Key = key.Key,
 | ||
|                 Code = lst.Max(x => x.Code),
 | ||
|                 Type = lst.Max(x => x.Type),
 | ||
|             }).ToList();
 | ||
| 
 | ||
|             var JsonData = JsonConvert.DeserializeObject<IDictionary<string, object>>(json);
 | ||
|             foreach (var item in list)
 | ||
|             {
 | ||
|                 try
 | ||
|                 {
 | ||
| 
 | ||
|                     if (!JsonData.ContainsKey(item.Key) || JsonData[item.Key]==null)
 | ||
|                     {
 | ||
|                         continue;
 | ||
|                     }
 | ||
|                     var value = JsonData[item.Key];
 | ||
|                     if (value.GetType() == typeof(JArray))
 | ||
|                     {
 | ||
|                         JArray arrays = (JArray)value;
 | ||
|                         if (item.Type.ToLower() == "id".ToLower())
 | ||
|                         {
 | ||
|                             List<Guid> guids = new List<Guid>();
 | ||
|                             arrays.ForEach(x =>
 | ||
|                             {
 | ||
|                                 guids.Add(Guid.Parse(x.ToString()));
 | ||
|                             });
 | ||
|                             JsonData[item.Key] = string.Join(',', await _dbContext.Dictionary.Where(x => guids.Contains(x.Id)).Select(x => x.ValueCN).ToListAsync());
 | ||
|                         }
 | ||
|                         else if (item.Type.ToLower() == "ChildGroup".ToLower())
 | ||
|                         {
 | ||
|                             List<string> guids = new List<string>();
 | ||
|                             arrays.ForEach(x =>
 | ||
|                             {
 | ||
|                                 guids.Add(x.ToString());
 | ||
|                             });
 | ||
|                             JsonData[item.Key] = string.Join(',', await
 | ||
|                                _dbContext.Dictionary.Where(x => x.Code == item.Code).GroupJoin(
 | ||
|                                     _dbContext.Dictionary.Where(x => guids.Contains(x.ChildGroup)), a => a.Id, b => b.ParentId, (a, b) => new
 | ||
|                                     {
 | ||
|                                         parent = b
 | ||
|                                     }).SelectMany(a => a.parent, (m, n) => new
 | ||
|                                     {
 | ||
|                                         value = n.ValueCN
 | ||
|                                     }).Select(x => x.value).ToListAsync()
 | ||
|                                     );
 | ||
|                         }
 | ||
|                         else
 | ||
|                         {
 | ||
|                             List<string> guids = new List<string>();
 | ||
|                             arrays.ForEach(x =>
 | ||
|                             {
 | ||
|                                 guids.Add(x.ToString());
 | ||
|                             });
 | ||
|                             JsonData[item.Key] = string.Join(',', await
 | ||
|                                 _dbContext.Dictionary.Where(x => x.Code == item.Code).GroupJoin(
 | ||
|                                      _dbContext.Dictionary.Where(x => guids.Contains(x.Code)), a => a.Id, b => b.ParentId, (a, b) => new
 | ||
|                                      {
 | ||
|                                          parent = b
 | ||
|                                      }).SelectMany(a => a.parent, (m, n) => new
 | ||
|                                      {
 | ||
|                                          value = n.ValueCN
 | ||
|                                      }).Select(x => x.value).ToListAsync()
 | ||
|                                     );
 | ||
|                         }
 | ||
|                     }
 | ||
|                     else
 | ||
|                     {
 | ||
|                         if (item.Type.ToLower() == "id".ToLower())
 | ||
|                         {
 | ||
|                             Guid guid = Guid.Parse(value.ToString());
 | ||
|                             JsonData[item.Key] = await _dbContext.Dictionary.Where(x => guid == x.Id).Select(x => x.ValueCN).FirstOrDefaultAsync();
 | ||
|                         }
 | ||
|                         else if (item.Type.ToLower() == "ChildGroup".ToLower())
 | ||
|                         {
 | ||
|                             JsonData[item.Key] = await _dbContext.Dictionary.Where(x => x.Code == item.Code).Join(_dbContext.Dictionary.Where(x => x.ChildGroup == value.ToString()), a => a.Id, b => b.ParentId, (a, b) => new
 | ||
|                             {
 | ||
|                                 value = b.ValueCN
 | ||
|                             }).Select(x => x.value).FirstOrDefaultAsync();
 | ||
|                         }
 | ||
|                         else
 | ||
|                         {
 | ||
|                             JsonData[item.Key] = await _dbContext.Dictionary.Where(x => x.Code == item.Code).Join(_dbContext.Dictionary.Where(x => x.Code == value.ToString()), a => a.Id, b => b.ParentId, (a, b) => new
 | ||
|                             {
 | ||
|                                 value = b.ValueCN
 | ||
|                             }).Select(x => x.value).FirstOrDefaultAsync();
 | ||
| 
 | ||
|                         }
 | ||
|                     }
 | ||
|                 }
 | ||
|                 catch (Exception)
 | ||
|                 {
 | ||
| 
 | ||
|                     //throw new BusinessValidationFailedException("Json 对象枚举异常");
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|             return JsonConvert.SerializeObject(JsonData);
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 添加稽查记录
 | ||
|         /// </summary>
 | ||
|         /// <param name="entity">实体</param>
 | ||
|         /// <param name="isSaveAudit">是否保存</param>
 | ||
|         /// <returns></returns>
 | ||
|         private async Task AddInspectionAsync(TEntity entity, bool isSaveAudit = false)
 | ||
|         {
 | ||
|             bool needsave = true;
 | ||
|             DataInspection inspectionData = new DataInspection()
 | ||
|             {
 | ||
|                 Identification = $"{GetRequestUrl()}/{ typeof(TEntity).ToString().Substring(typeof(TEntity).ToString().LastIndexOf('.') + 1)}/Add",
 | ||
|             };
 | ||
| 
 | ||
| 
 | ||
|             MapData(entity, inspectionData);
 | ||
| 
 | ||
|             var createtime = DateTime.Now;
 | ||
|             // 项目
 | ||
|             if (typeof(TEntity) == typeof(Trial))
 | ||
|             {
 | ||
|                 Trial data = entity as Trial;
 | ||
|                 inspectionData = new DataInspection()
 | ||
|                 {
 | ||
|                     TrialId = data.Id,
 | ||
|                     SubjectId = data.Id,
 | ||
|                     TrialName = data.ExperimentName,
 | ||
|                     ResearchProgramNo = data.ResearchProgramNo,
 | ||
|                     IsSign = false,
 | ||
|                     CreateTime = createtime,
 | ||
|                     Identification = "Init|Trial|Status|Trial Setting-Infomation",   // 初始化项目
 | ||
|                     JsonDetail = entity.ToJcJson()
 | ||
|                 };
 | ||
|             }
 | ||
|             // 项目人员
 | ||
|             else if (typeof(TEntity) == typeof(TrialUser))
 | ||
|             {
 | ||
| 
 | ||
|             }
 | ||
|             // 受试者
 | ||
|             else if (typeof(TEntity) == typeof(Subject))
 | ||
|             {
 | ||
|                 Subject data = entity as Subject;
 | ||
|                 inspectionData = new DataInspection()
 | ||
|                 {
 | ||
|                     TrialId = data.TrialId,
 | ||
|                     SiteId = data.SiteId,
 | ||
|                     SubjectId = data.Id,
 | ||
|                     SubjectCode = data.Code,
 | ||
|                     IsSign = false,
 | ||
|                     CreateTime = createtime,
 | ||
|                     Identification = "Init|Subject|Status|Subject",   // 初始化受试者信息
 | ||
|                     JsonDetail = entity.ToJcJson()
 | ||
|                 };
 | ||
|             }
 | ||
| 
 | ||
|             // Dicom序列   // 移动不进来
 | ||
|             //if (typeof(TEntity) == typeof(DicomSeries))
 | ||
|             //{
 | ||
|             //    DicomSeries dicomStudy = entity as DicomSeries;
 | ||
|             //    datas.Add(new DataInspection()
 | ||
|             //    {
 | ||
| 
 | ||
|             //        SiteId = dicomStudy.SiteId,
 | ||
|             //        SubjectId = dicomStudy.SubjectId,
 | ||
|             //        TrialId = dicomStudy.TrialId,
 | ||
|             //        GeneralId = dicomStudy.StudyId,
 | ||
|             //        SubjectVisitId = dicomStudy.SubjectVisitId,
 | ||
|             //        CreateTime = createtime.AddMilliseconds(10),
 | ||
|             //        Identification = "Init|DICOM Series|Status|Visit-Image Upload",
 | ||
|             //        JsonDetail = JsonConvert.SerializeObject(new
 | ||
|             //        {
 | ||
|             //            StudyCode = dicomStudy.StudyCode,
 | ||
|             //            Modalities = dicomStudy.Modalities,
 | ||
|             //            SeriesNumber = dicomSeries.SeriesNumber,
 | ||
|             //            InstanceCount = dicomSeries.InstanceCount,
 | ||
|             //            SeriesTime = dicomSeries.SeriesTime,
 | ||
|             //            IsReading = dicomSeries.IsReading,
 | ||
|             //            IsDeleted = dicomSeries.IsReading,
 | ||
| 
 | ||
|             //        })
 | ||
|             //    });
 | ||
|             //}
 | ||
|             // dicom影像
 | ||
|             else if (typeof(TEntity) == typeof(DicomStudy))
 | ||
|             {
 | ||
|                 DicomStudy data = entity as DicomStudy;
 | ||
|                 await UpdateSubjectVisit(data.SubjectVisitId, SubmitStateEnum.ToSubmit, "上传Dicom影像");
 | ||
|             }
 | ||
|             // 非Dicom影像
 | ||
|             else if (typeof(TEntity) == typeof(NoneDicomStudyFile))
 | ||
|             {
 | ||
|                 NoneDicomStudyFile data = entity as NoneDicomStudyFile;
 | ||
|                 var subjectVisitId = await _dbContext.NoneDicomStudy.Where(x => x.Id == data.NoneDicomStudyId).Select(x => x.SubjectVisitId).FirstOrDefaultAsync();
 | ||
|                 await UpdateSubjectVisit(subjectVisitId, SubmitStateEnum.ToSubmit, "上传非Dicom影像");
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 needsave = false;
 | ||
|             }
 | ||
| 
 | ||
|             // 修改访视状态记录稽查
 | ||
|             async Task UpdateSubjectVisit(Guid subvisitVisit, SubmitStateEnum submit, string reason)
 | ||
|             {
 | ||
|                 var subjectvisit = await _dbContext.SubjectVisit.AsNoTracking().AsQueryable().Where(x => x.Id == subvisitVisit).FirstOrDefaultAsync();
 | ||
|                 if (subjectvisit.SubmitState != submit)
 | ||
|                 {
 | ||
|                     subjectvisit.SubmitState = submit;
 | ||
| 
 | ||
|                     inspectionData = new DataInspection()
 | ||
|                     {
 | ||
|                         Identification = "Edit|Visit|Status|Visit-Image Upload|Add Image",
 | ||
|                         TrialId = subjectvisit.TrialId,
 | ||
|                         SiteId = subjectvisit.SiteId,
 | ||
|                         SubjectId = subjectvisit.SubjectId,
 | ||
|                         SubjectVisitId = subjectvisit.Id,
 | ||
|                         Reason = reason,
 | ||
|                         CreateTime = createtime.AddMilliseconds(100),
 | ||
|                         JsonDetail = subjectvisit.ToJcJson(),
 | ||
|                     };
 | ||
|                 }
 | ||
| 
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|             if (needsave)
 | ||
|             {
 | ||
|                 await AddInspectionRecordAsync(inspectionData, entity);
 | ||
|             }
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 获取URl参数
 | ||
|         /// </summary>
 | ||
|         /// <returns></returns>
 | ||
|         private string GetRequestUrl()
 | ||
|         {
 | ||
|             return _userInfo.RequestUrl;
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 映射数据
 | ||
|         /// </summary>
 | ||
|         /// <param name="data"></param>
 | ||
|         /// <param name="mapData">要赋值的对象</param>
 | ||
|         private void MapData(dynamic data, dynamic mapData)
 | ||
|         {
 | ||
|             List<string> column = new List<string>() { "TrialId", "SiteId", "SubjectId", "SubjectVisitId", "CreateUserName", "TrialName", "SiteName", "SubjectCode", "SubjectVisitName", "RoleName", "SiteCode", "ResearchProgramNo" };
 | ||
|             foreach (var item in column)
 | ||
|             {
 | ||
|                 try
 | ||
|                 {
 | ||
|                     var i = mapData.GetType().GetProperty(item).GetValue(mapData);
 | ||
|                     if (i == null)
 | ||
|                     {
 | ||
|                         var value = data.GetType().GetProperty(item).GetValue(data);
 | ||
|                         mapData.GetType().GetProperty(item).SetValue(mapData, value);
 | ||
|                     }
 | ||
| 
 | ||
|                 }
 | ||
|                 catch (Exception)
 | ||
|                 {
 | ||
|                     continue;
 | ||
| 
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 添加稽查记录
 | ||
|         /// </summary>
 | ||
|         /// <param name="add">稽查数据</param>
 | ||
|         /// <param name="data">实体信息</param>
 | ||
|         /// <returns></returns>
 | ||
|         public async Task AddInspectionRecordAsync(DataInspection add, dynamic data)
 | ||
|         {
 | ||
|             InspectionGeneralData generalData = new InspectionGeneralData();
 | ||
|             MapData(add, generalData);
 | ||
|             await SetInspectionNameValue(generalData);
 | ||
|             #region 处理标识
 | ||
|             try
 | ||
|             {
 | ||
|                 var from = await _dbContext.FrontAuditConfig.FirstOrDefaultAsync(x => x.Identification == add.Identification);
 | ||
|                 add.ObjectType = from?.ObjectTypeId;
 | ||
|                 add.OptType = from?.OptTypeId;
 | ||
|                 add.ChildrenType = from?.ChildrenTypeId;
 | ||
|                 add.ModuleType = from?.ModuleTypeId;
 | ||
|             }
 | ||
|             catch (Exception)
 | ||
|             {
 | ||
| 
 | ||
|                 throw new BusinessValidationFailedException("操作标识异常");
 | ||
|             }
 | ||
|             #endregion
 | ||
|             if (add.ParentId == null)
 | ||
|             {
 | ||
|                 add.ParentId = (await _dbContext.DataInspection.AsQueryable().Where(x => x.TrialId == add.TrialId && x.SubjectVisitId == add.SubjectVisitId && x.SubjectId == add.SubjectId && x.SiteId == add.SiteId && x.ChildrenType == add.ChildrenType && x.ObjectType == add.ObjectType && x.VisitStageId == add.VisitStageId && x.GeneralId == add.GeneralId).OrderByDescending(x => x.CreateTime).FirstOrDefaultAsync())?.Id;
 | ||
| 
 | ||
|             }
 | ||
|             add.CreateUserId = _userInfo.Id;
 | ||
|             add.IP = _userInfo.IP;
 | ||
|             if (add.CreateTime == default(DateTime))
 | ||
|             {
 | ||
|                 add.CreateTime = DateTime.Now;
 | ||
|             }
 | ||
|             var inspectionData = new InspectionData()
 | ||
|             {
 | ||
|                 Data = data,
 | ||
|                 Inspection = generalData
 | ||
|             };
 | ||
| 
 | ||
|             add.JsonDetail = inspectionData.ToJcJson();
 | ||
|             await SetDataInspectionDateType(add);
 | ||
| 
 | ||
|             await _dbContext.DataInspection.AddAsync(add);
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 添加稽查记录
 | ||
|         /// </summary>
 | ||
|         /// <param name="datas"></param>
 | ||
|         /// <returns></returns>
 | ||
|         public async Task AddListInspectionRecordAsync(List<DataInspection> datas)
 | ||
|         {
 | ||
| 
 | ||
|             //var trialIds= datas.Select(x=>x.TrialId).Distinct().ToList();
 | ||
|             //var subjectVisitIds= datas.Select(x=>x.SubjectVisitId).Distinct().ToList();
 | ||
|             //var subjectIds = datas.Select(x => x.SubjectId).Distinct().ToList();
 | ||
|             //var siteIds = datas.Select(x => x.SiteId).Distinct().ToList();
 | ||
|             //var childrenTypes= datas.Select(x => x.ChildrenType).Distinct().ToList();
 | ||
|             //var objectTypes = datas.Select(x => x.ObjectType).Distinct().ToList();
 | ||
| 
 | ||
|             foreach (var add in datas)
 | ||
|             {
 | ||
|                 await SetInspectionNameValue(add);
 | ||
|                 if (add.ParentId == null)
 | ||
|                 {
 | ||
|                     add.ParentId = (await _dbContext.DataInspection.AsQueryable().Where(x => x.TrialId == add.TrialId && x.SubjectVisitId == add.SubjectVisitId && x.SubjectId == add.SubjectId && x.SiteId == add.SiteId && x.ChildrenType == add.ChildrenType && x.ObjectType == add.ObjectType && x.VisitStageId == add.VisitStageId && x.GeneralId == add.GeneralId).OrderByDescending(x => x.CreateTime).FirstOrDefaultAsync())?.Id;
 | ||
| 
 | ||
|                 }
 | ||
|                 add.CreateUserId = _userInfo.Id;
 | ||
|                 add.IP = _userInfo.IP;
 | ||
|                 if (add.CreateTime == default(DateTime))
 | ||
|                 {
 | ||
|                     add.CreateTime = DateTime.Now;
 | ||
|                 }
 | ||
|                 //add.JsonDetail = await SetEnum(add.TrialId, add.Identification, add.JsonDetail);
 | ||
|                 await SetDataInspectionDateType(add);
 | ||
|             }
 | ||
| 
 | ||
|             //await _dbContext.DataInspection.AddRangeAsync(datas);
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 格式化日期和时间
 | ||
|         /// </summary>
 | ||
|         /// <param name="Data">稽查数据</param>
 | ||
|         /// <returns></returns>
 | ||
|         public async Task<DataInspection> SetDataInspectionDateType(DataInspection Data)
 | ||
|         {
 | ||
|             var list = await (from parent in _dbContext.FrontAuditConfig.AsQueryable().Where(x => x.Identification == Data.Identification)
 | ||
|                               join child in _dbContext.FrontAuditConfig.AsQueryable().Where(x => x.EnumType == "Date") on parent.Id equals child.ParentId
 | ||
|                               select new DateDto()
 | ||
|                               {
 | ||
|                                   Code = child.Code,
 | ||
|                                   DateType = child.DateType,
 | ||
|                               }).ToListAsync();
 | ||
| 
 | ||
|             var JsonData = JsonConvert.DeserializeObject<IDictionary<string, object>>(Data.JsonDetail);
 | ||
| 
 | ||
|             foreach (var item in JsonData.Keys)
 | ||
|             {
 | ||
|                 var datefirst = list.FirstOrDefault(x => x.Code.ToLower() == item.ToLower());
 | ||
|                 if (datefirst != null && !IsNullOrEmpty(JsonData[item]))
 | ||
|                 {
 | ||
|                     try
 | ||
|                     {
 | ||
|                         if (datefirst.DateType == "Date")
 | ||
|                         {
 | ||
|                             JsonData[item] = DateTime.Parse(JsonData[item].ToString()).ToString("yyyy-MM-dd");
 | ||
|                         }
 | ||
| 
 | ||
|                         if (datefirst.DateType == "DateTime")
 | ||
|                         {
 | ||
|                             JsonData[item] = DateTime.Parse(JsonData[item].ToString()).ToString("yyyy-MM-dd HH:mm:ss");
 | ||
|                         }
 | ||
|                     }
 | ||
|                     catch (Exception)
 | ||
|                     {
 | ||
|                         continue;
 | ||
|                     }
 | ||
|                 }
 | ||
| 
 | ||
|             }
 | ||
|             Data.JsonDetail = JsonConvert.SerializeObject(JsonData);
 | ||
| 
 | ||
|             return Data;
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// IsNullOrEmpty
 | ||
|         /// </summary>
 | ||
|         /// <param name="value"></param>
 | ||
|         /// <returns></returns>
 | ||
|         private bool IsNullOrEmpty(object value)
 | ||
|         {
 | ||
|             if (value == null || value.ToString() == string.Empty)
 | ||
|             {
 | ||
|                 return true;
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 return false;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 设置项目以及名称
 | ||
|         /// </summary>
 | ||
|         /// <param name="Data"></param>
 | ||
|         /// <returns></returns>
 | ||
|         public async Task SetInspectionNameValue(DataInspection Data)
 | ||
|         {
 | ||
|             #region 项目名称
 | ||
| 
 | ||
|             var trialdata = await _dbContext.Trial.Select(x => new { x.Id, x.ResearchProgramNo, x.ExperimentName, }).FirstOrDefaultAsync(x => x.Id == Data.TrialId);
 | ||
|             if (IsNullOrEmpty(Data.ResearchProgramNo))
 | ||
|             {
 | ||
| 
 | ||
|                 Data.ResearchProgramNo = trialdata?.ResearchProgramNo;
 | ||
|             }
 | ||
| 
 | ||
|             if (IsNullOrEmpty(Data.TrialName))
 | ||
|             {
 | ||
|                 Data.TrialName = trialdata?.ExperimentName;
 | ||
|             }
 | ||
|             #endregion
 | ||
| 
 | ||
|             #region 测试中心名称
 | ||
| 
 | ||
| 
 | ||
|             Data.SiteCode = (await _dbContext.TrialSite.IgnoreQueryFilters().FirstOrDefaultAsync(x => x.TrialId == Data.TrialId && x.SiteId == Data.SiteId))?.TrialSiteCode;
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|             if (IsNullOrEmpty(Data.SiteName) && Data.SiteId != null)
 | ||
|             {
 | ||
|                 var sitedata = await _dbContext.Site.Where(x => x.Id == Data.SiteId).Select(x => new { x.SiteName }).FirstOrDefaultAsync();
 | ||
|                 Data.SiteName = sitedata?.SiteName;
 | ||
|             }
 | ||
|             #endregion
 | ||
| 
 | ||
|             #region 受试者
 | ||
| 
 | ||
| 
 | ||
|             if (IsNullOrEmpty(Data.SubjectCode) && Data.SubjectId != null)
 | ||
|             {
 | ||
| 
 | ||
|                 Data.SubjectCode = (await _dbContext.Subject.Where(x => x.Id == Data.SubjectId).Select(x => new { x.Code }).FirstOrDefaultAsync())?.Code;
 | ||
|             }
 | ||
|             #endregion
 | ||
| 
 | ||
|             #region 访视
 | ||
|             if (IsNullOrEmpty(Data.SubjectVisitName))
 | ||
|             {
 | ||
|                 Data.SubjectVisitName = (await _dbContext.SubjectVisit.Where(x => x.Id == Data.SubjectVisitId).Select(x => new { x.VisitName }).FirstOrDefaultAsync())?.VisitName;
 | ||
|             }
 | ||
|             #endregion
 | ||
| 
 | ||
|             #region 创建者
 | ||
| 
 | ||
|             if (IsNullOrEmpty(Data.CreateUserName))
 | ||
|             {
 | ||
|                 Data.CreateUserName = _userInfo.RealName;
 | ||
|             }
 | ||
| 
 | ||
|             if (IsNullOrEmpty(Data.RoleName))
 | ||
|             {
 | ||
|                 Data.RoleName = _userInfo.UserTypeShortName;
 | ||
|             }
 | ||
| 
 | ||
|             //if (IsNullOrEmpty(Data.CreateUserName) || IsNullOrEmpty(Data.RoleName))
 | ||
|             //{
 | ||
|             //    var userdata = await _dbContext.Users.AsQueryable().Where(x => x.Id == Data.CreateUserId).GroupJoin(_dbContext.UserType.AsQueryable(), a => a.UserTypeId, b => b.Id, (a, b) => new
 | ||
|             //    {
 | ||
|             //        UserName = a.FirstName + a.LastName,
 | ||
|             //        Role = b
 | ||
|             //    }).SelectMany(a => a.Role, (m, n) => new
 | ||
|             //    {
 | ||
|             //        UserName = m.UserName,
 | ||
|             //        RoleName = n.UserTypeShortName
 | ||
|             //    }).FirstOrDefaultAsync();
 | ||
| 
 | ||
|             //    if (userdata != null)
 | ||
|             //    {
 | ||
|             //        if (IsNullOrEmpty(Data.CreateUserName))
 | ||
|             //        {
 | ||
|             //            Data.CreateUserName = userdata?.UserName;
 | ||
|             //        }
 | ||
| 
 | ||
| 
 | ||
|             //        if (IsNullOrEmpty(Data.RoleName))
 | ||
|             //        {
 | ||
|             //            Data.RoleName = userdata?.RoleName;
 | ||
|             //        }
 | ||
|             //    }
 | ||
|             //}
 | ||
|             #endregion
 | ||
| 
 | ||
|             #region 取操作类型
 | ||
|             try
 | ||
|             {
 | ||
|                 var from = await _dbContext.FrontAuditConfig.FirstOrDefaultAsync(x => x.Identification == Data.Identification);
 | ||
|                 Data.ObjectType = from.ObjectTypeId;
 | ||
|                 Data.OptType = from.OptTypeId;
 | ||
|                 Data.ChildrenType = from.ChildrenTypeId;
 | ||
|                 Data.ModuleType = from.ModuleTypeId;
 | ||
|             }
 | ||
|             catch (Exception)
 | ||
|             {
 | ||
| 
 | ||
|                 throw new BusinessValidationFailedException("操作标识异常");
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|             #endregion
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 设置项目以及名称
 | ||
|         /// </summary>
 | ||
|         /// <param name="Data"></param>
 | ||
|         /// <returns></returns>
 | ||
|         public async Task SetInspectionNameValue(InspectionGeneralData Data)
 | ||
|         {
 | ||
|             #region 项目名称
 | ||
| 
 | ||
|             var trialdata = await _dbContext.Trial.Select(x => new { x.Id, x.ResearchProgramNo, x.ExperimentName, }).FirstOrDefaultAsync(x => x.Id == Data.TrialId);
 | ||
|             if (IsNullOrEmpty(Data.ResearchProgramNo))
 | ||
|             {
 | ||
| 
 | ||
|                 Data.ResearchProgramNo = trialdata?.ResearchProgramNo;
 | ||
|             }
 | ||
| 
 | ||
|             if (IsNullOrEmpty(Data.TrialName))
 | ||
|             {
 | ||
|                 Data.TrialName = trialdata?.ExperimentName;
 | ||
|             }
 | ||
|             #endregion
 | ||
| 
 | ||
|             #region 测试中心名称
 | ||
| 
 | ||
| 
 | ||
|             Data.SiteCode = (await _dbContext.TrialSite.IgnoreQueryFilters().FirstOrDefaultAsync(x => x.TrialId == Data.TrialId && x.SiteId == Data.SiteId))?.TrialSiteCode;
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|             if (IsNullOrEmpty(Data.SiteName) && Data.SiteId != null)
 | ||
|             {
 | ||
|                 var sitedata = await _dbContext.Site.Where(x => x.Id == Data.SiteId).Select(x => new { x.SiteName }).FirstOrDefaultAsync();
 | ||
|                 Data.SiteName = sitedata?.SiteName;
 | ||
|             }
 | ||
|             #endregion
 | ||
| 
 | ||
|             #region 受试者
 | ||
| 
 | ||
| 
 | ||
|             if (IsNullOrEmpty(Data.SubjectCode) && Data.SubjectId != null)
 | ||
|             {
 | ||
| 
 | ||
|                 Data.SubjectCode = (await _dbContext.Subject.Where(x => x.Id == Data.SubjectId).Select(x => new { x.Code }).FirstOrDefaultAsync())?.Code;
 | ||
|             }
 | ||
|             #endregion
 | ||
| 
 | ||
|             #region 访视
 | ||
|             if (IsNullOrEmpty(Data.SubjectVisitName))
 | ||
|             {
 | ||
|                 Data.SubjectVisitName = (await _dbContext.SubjectVisit.Where(x => x.Id == Data.SubjectVisitId).Select(x => new { x.VisitName }).FirstOrDefaultAsync())?.VisitName;
 | ||
|             }
 | ||
|             #endregion
 | ||
| 
 | ||
|             #region 创建者
 | ||
| 
 | ||
|             if (IsNullOrEmpty(Data.CreateUserName))
 | ||
|             {
 | ||
|                 Data.CreateUserName = _userInfo.RealName;
 | ||
|             }
 | ||
| 
 | ||
|             if (IsNullOrEmpty(Data.RoleName))
 | ||
|             {
 | ||
|                 Data.RoleName = _userInfo.UserTypeShortName;
 | ||
|             }
 | ||
|             #endregion
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         }
 | ||
|         #endregion
 | ||
| 
 | ||
| 
 | ||
|         #region 异步查询
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         public async Task<TResult> MaxAsync<TResult>(Expression<Func<TEntity, TResult>> selector)
 | ||
|         {
 | ||
| 
 | ||
|             return await _dbSet.AsNoTracking().MaxAsync(selector);
 | ||
|         }
 | ||
| 
 | ||
|         public async Task<bool> AnyAsync(Expression<Func<TEntity, bool>> exp, bool ignoreQueryFilters = false)
 | ||
|         {
 | ||
|             var query = _dbSet.AsQueryable();
 | ||
| 
 | ||
|             if (ignoreQueryFilters)
 | ||
|             {
 | ||
|                 query = query.IgnoreQueryFilters();
 | ||
|             }
 | ||
| 
 | ||
|             return await query.AsNoTracking().AnyAsync(exp);
 | ||
|         }
 | ||
| 
 | ||
|         public async Task<int> CountAsync(Expression<Func<TEntity, bool>> whereLambda = null, bool ignoreQueryFilters = false)
 | ||
|         {
 | ||
|             var query = _dbSet.AsQueryable();
 | ||
| 
 | ||
|             if (ignoreQueryFilters)
 | ||
|             {
 | ||
|                 query = query.IgnoreQueryFilters();
 | ||
|             }
 | ||
| 
 | ||
|             return whereLambda == null ? await query.AsNoTracking().CountAsync() : await query.AsNoTracking().CountAsync(whereLambda);
 | ||
|         }
 | ||
| 
 | ||
|         public async ValueTask<TEntity> FindAsync(Guid id, CancellationToken cancellationToken = default)
 | ||
|         {
 | ||
|             return await _dbContext.FindAsync<TEntity>(id);
 | ||
|         }
 | ||
| 
 | ||
|         //有可能是联合主键,本项目没用到,用Guid
 | ||
|         public async ValueTask<TEntity> FindAsync(object[] keyValues, CancellationToken cancellationToken)
 | ||
|         {
 | ||
|             return await _dbContext.FindAsync<TEntity>(keyValues);
 | ||
|         }
 | ||
| 
 | ||
|         public async Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> exp = null, bool ignoreQueryFilters = false)
 | ||
|         {
 | ||
| 
 | ||
|             var query = _dbSet.AsQueryable();
 | ||
| 
 | ||
|             if (ignoreQueryFilters)
 | ||
|             {
 | ||
|                 query = query.IgnoreQueryFilters();
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|             if (exp != null)
 | ||
|             {
 | ||
|                 query = query.Where(exp);
 | ||
|             }
 | ||
| 
 | ||
|             return await query.FirstOrDefaultAsync().ConfigureAwait(false);
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 不跟踪
 | ||
|         /// </summary>
 | ||
|         /// <param name="exp"></param>
 | ||
|         /// <param name="ignoreQueryFilters"></param>
 | ||
|         /// <returns></returns>
 | ||
|         public async Task<TEntity> FirstOrDefaultNoTrackingAsync(Expression<Func<TEntity, bool>> exp = null, bool ignoreQueryFilters = false)
 | ||
|         {
 | ||
| 
 | ||
|             var query = _dbSet.AsNoTracking().AsQueryable();
 | ||
| 
 | ||
|             if (ignoreQueryFilters)
 | ||
|             {
 | ||
|                 query = query.IgnoreQueryFilters();
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|             if (exp != null)
 | ||
|             {
 | ||
|                 query = query.Where(exp);
 | ||
|             }
 | ||
| 
 | ||
|             return await query.AsNoTracking().FirstOrDefaultAsync().ConfigureAwait(false);
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
|         #endregion
 | ||
| 
 | ||
| 
 | ||
|         #region 非异步部分
 | ||
| 
 | ||
|         public TEntity ImageFind(Guid id, Type type)
 | ||
|         {
 | ||
|             //重传的时候  状态为修改    上传的时候状态为添加  内存中有,就不要重复查询数据库了
 | ||
|             var list = _dbContext.ChangeTracker.Entries()
 | ||
|                   .Where(u => (u.State == EntityState.Added || u.State == EntityState.Modified) && (u.Entity.GetType() == type)).Select(t => t.Entity as TEntity);
 | ||
| 
 | ||
|             var entity = list.FirstOrDefault(t => t.Id == id);
 | ||
| 
 | ||
|             if (entity == null)
 | ||
|             {
 | ||
|                 return _dbSet.FirstOrDefault(t => t.Id == id);
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 return entity;
 | ||
|             }
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
|         public IQueryable<TEntity> AsQueryable(bool ignoreQueryFilters = false)
 | ||
|         {
 | ||
|             var query = _dbSet.AsQueryable();
 | ||
| 
 | ||
|             if (ignoreQueryFilters)
 | ||
|             {
 | ||
|                 query = query.IgnoreQueryFilters();
 | ||
|             }
 | ||
| 
 | ||
|             return query.AsNoTracking();
 | ||
|         }
 | ||
| 
 | ||
|         public IQueryable<TResult> Select<TResult>(Expression<Func<TEntity, TResult>> selector)
 | ||
|         {
 | ||
|             return _dbSet.AsNoTracking().Select(selector);
 | ||
|         }
 | ||
| 
 | ||
|         public IQueryable<TEntity> WhereIf(bool condition, Expression<Func<TEntity, bool>> filter)
 | ||
|         {
 | ||
|             return condition ? _dbSet.AsNoTracking().Where(filter) : _dbSet.AsNoTracking();
 | ||
|         }
 | ||
| 
 | ||
|         public IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> exp = null, bool isTraking = false, bool ignoreQueryFilters = false)
 | ||
|         {
 | ||
|             IQueryable<TEntity> query = _dbSet;
 | ||
| 
 | ||
|             if (!isTraking)
 | ||
|             {
 | ||
|                 query = query.AsNoTracking();
 | ||
|             }
 | ||
| 
 | ||
|             if (ignoreQueryFilters)
 | ||
|             {
 | ||
|                 query = query.IgnoreQueryFilters();
 | ||
|             }
 | ||
| 
 | ||
|             if (exp != null)
 | ||
|             {
 | ||
|                 query = query.Where(exp);
 | ||
|             }
 | ||
|             return query;
 | ||
|         }
 | ||
| 
 | ||
|         public EntityEntry Entry(TEntity t)
 | ||
|         {
 | ||
|             return _dbContext.Entry(t);
 | ||
|         }
 | ||
| 
 | ||
|         public EntityEntry<TEntity> Attach(TEntity entity)
 | ||
|         {
 | ||
|             return _dbSet.Attach(entity);
 | ||
|         }
 | ||
| 
 | ||
|         public void Detached(TEntity t)
 | ||
|         {
 | ||
|             _dbContext.Entry(t).State = EntityState.Detached;
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         //  automapper 相关
 | ||
|         public IQueryable<TDestination> ProjectTo<TDestination>(IConfigurationProvider configuration, object parameters, params Expression<Func<TDestination, object>>[] membersToExpand)
 | ||
|         {
 | ||
|             return _dbSet.AsNoTracking().ProjectTo(configuration, parameters, membersToExpand);
 | ||
|         }
 | ||
| 
 | ||
|         public IQueryable<TDestination> ProjectTo<TDestination>(IConfigurationProvider configuration, params Expression<Func<TDestination, object>>[] membersToExpand)
 | ||
|         {
 | ||
|             return _dbSet.AsNoTracking().ProjectTo(configuration, membersToExpand);
 | ||
|         }
 | ||
| 
 | ||
|         public IQueryable<TDestination> ProjectTo<TDestination>(IConfigurationProvider configuration, IDictionary<string, object> parameters, params string[] membersToExpand)
 | ||
|         {
 | ||
|             return _dbSet.AsNoTracking().ProjectTo<TDestination>(configuration, parameters, membersToExpand);
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         #endregion
 | ||
| 
 | ||
|         #region 待废弃
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 仅仅供字典表插入使用,因为efcore 动态映射列的问题
 | ||
|         /// </summary>
 | ||
|         /// <typeparam name="TFrom"></typeparam>
 | ||
|         /// <param name="from"></param>
 | ||
|         /// <param name="verify"></param>
 | ||
|         /// <returns></returns>
 | ||
|         /// <exception cref="BusinessValidationFailedException"></exception>
 | ||
|         public async Task<TEntity> InsertDictionaryAsync<TFrom>(TFrom from, params EntityVerifyExp<TEntity>[] verify)
 | ||
|         {
 | ||
|             var entity = _mapper.Map<TEntity>(from);
 | ||
| 
 | ||
| 
 | ||
|             foreach (var verifyItem in verify.Where(t => t.verifyType != VerifyEnum.OnlyUpdate && t.IsVerify))
 | ||
|             {
 | ||
|                 if (await _dbSet.IgnoreQueryFilters().AnyAsync(verifyItem.VerifyExp).ConfigureAwait(false))
 | ||
|                 {
 | ||
|                     throw new BusinessValidationFailedException(verifyItem.VerifyMsg);
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|             if (typeof(TEntity) == typeof(Dictionary))
 | ||
|             {
 | ||
|                 Type type = typeof(TFrom);
 | ||
| 
 | ||
|                 //以下是不要ID这个字段的  比如自增列ID  就不能像上名那样写   
 | ||
|                 var properties = type.GetProperties().Where(t => t.Name != "Id");
 | ||
| 
 | ||
| 
 | ||
|                 string strSqlName = string.Join(",", properties.Select(p => $"[{p.Name}]").ToArray());
 | ||
| 
 | ||
|                 string strSqlValue = string.Join(",", properties.Select(P => $"@{P.Name}").ToArray());
 | ||
| 
 | ||
|                 string strSql = $"insert into {nameof(Dictionary)} ( " + strSqlName + " ) values (" + strSqlValue + ")";
 | ||
| 
 | ||
|                 //para Sql是参数
 | ||
|                 SqlParameter[] para = properties.Select(p => new SqlParameter($"@{p.Name}", p.GetValue(from, null))).ToArray();
 | ||
| 
 | ||
| 
 | ||
|                 _dbContext.Database.ExecuteSqlRaw(strSql, para);
 | ||
| 
 | ||
|                 return entity;
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 throw new Exception("仅仅供字典表插入使用,因为efcore 动态映射列的问题");
 | ||
|                 //await _dbSet.BulkInsertAsync(new List<TEntity>() { entity });
 | ||
| 
 | ||
|                 //return entity;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         public async Task<bool> AddRangeAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
 | ||
|         {
 | ||
|             await _dbSet.AddRangeAsync(entities).ConfigureAwait(false);
 | ||
| 
 | ||
|             if (autoSave)
 | ||
|             {
 | ||
|                 return await SaveChangesAsync(cancellationToken);
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 return false;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         #endregion
 | ||
|     }
 | ||
| 
 | ||
| }
 |