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 IRaCIS.Core.Infra.EFCore.Dto; using Newtonsoft.Json.Linq; using IRaCIS.Core.Domain.Common; namespace IRaCIS.Core.Infra.EFCore { public class Repository : IRepository where TEntity : Entity, new() { public IMapper _mapper { get; set; } public IRaCISDBContext _dbContext { get; set; } public DbSet _dbSet => _dbContext.Set(); public IUserInfo _userInfo { get; set; } public Repository(IRaCISDBContext dbContext, IMapper mapper, IUserInfo userInfo) { _dbContext = dbContext; _mapper = mapper; _userInfo = userInfo; } #region 异步 EF 跟踪 添加 public async Task> AddRangeAsync(IEnumerable entities, bool isSaveAudit = false) { foreach (var addEntity in entities) { await AddAsync(addEntity, isSaveAudit); } return entities; } /// EF跟踪方式 添加 public async ValueTask 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 InsertFromDTOAsync(TFrom from, bool autoSave = false, params EntityVerifyExp[] verify) { var entity = _mapper.Map(from); await EntityVerifyAsync(true, verify); entity = await AddAsync(entity, autoSave); return entity; } #endregion #region 异步 EF 跟踪 部分字段更新 /// 用前端传递的视图模型字段,更新,同时返回数据库该条记录的原始信息,方便对比某些字段是否更改,进行相应的逻辑操作 public async Task UpdateFromDTOAsync(TFrom from, bool autoSave = false, bool ignoreDtoNullProperty = true, params EntityVerifyExp[] verify) { var entity = _mapper.Map(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; } /// EF跟踪方式 生成 部分字段更新, 通过主键id 和表达式树 更新部分字段 /// 例如 Guid.Parse("8a90c96e-0776-4f7b-82a6-18933d339584"),u => new Dictionary() { ParentId = null, Code = "test" }默认会去处理更新更新人 更新时间 public async Task UpdateNoQueryAsync(Guid id, Expression> updateFactory, bool autoSave = false, params EntityVerifyExp[] verify) { await SetPartialFieldUpdateAsync(id, updateFactory, verify); await SaveChangesAsync(autoSave); } /// EF跟踪方式 生成 部分字段立即更新,默认会去处理更新更新人 更新时间 public async Task UpdateNowNoQueryAsync(Guid id, Expression> updateFactory, params EntityVerifyExp[] verify) { await SetPartialFieldUpdateAsync(id, updateFactory, verify); return await SaveChangesAsync(true); } /// 注意 模型标注了 ConcurrencyCheck的属性,这样的实体,不适合用部分字段更新,ef生成的更新sql会自动带上ConcurrencyCheck的属性条件 private async Task SetPartialFieldUpdateAsync(Guid id, Expression> updateFactory, params EntityVerifyExp[] verify) { await EntityVerifyAsync(false, verify, id); var entity = new TEntity() { Id = id }; var entityEntry = _dbContext.Entry(entity); entityEntry.State = EntityState.Detached; List list = ((MemberInitExpression)updateFactory.Body).Bindings.Select(mb => mb.Member.Name) .Select(propName => typeof(TEntity).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)).ToList(); Func 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 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 跟踪 自动生成 更新 和删除语句 /// EF跟踪方式 更新,全字段更新 不好 public async Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { _dbSet.Update(entity); if (autoSave) { return await SaveChangesAsync(cancellationToken); } else { return false; } } /// EF跟踪方式 外层先有查询好的完成实体,再更新部分字段 稽查的时候需要完整的实体信息 public async Task UpdateAsync(TEntity waitModifyEntity, Expression> updateFactory, bool autoSave = false, CancellationToken cancellationToken = default) { var entityEntry = _dbContext.Entry(waitModifyEntity); entityEntry.State = EntityState.Detached; ModifyPartialFiled(waitModifyEntity, updateFactory); return await SaveChangesAsync(autoSave); } /// EF跟踪方式 先查询出来,再更新部分字段 稽查的时候需要完整的实体信息 public async Task UpdateFromQueryAsync(Guid id, Expression> updateFactory, bool autoSave = false, bool ignoreQueryFilter = false, CancellationToken cancellationToken = default) { var query = ignoreQueryFilter ? _dbSet.AsNoTracking().IgnoreQueryFilters() : _dbSet.AsNoTracking(); //不跟踪 查询出来的实体就是Detached var searchEntity = await query.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 UpdateFromQueryAsync(Expression> updateFilter, Expression> 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); } } /// 更新后拥有完整的实体信息,便于稽查 private void ModifyPartialFiled(TEntity waitModifyEntity, Expression> updateFactory) { List list = ((MemberInitExpression)updateFactory.Body).Bindings.Select(mb => mb.Member.Name) .Select(propName => typeof(TEntity).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)).ToList(); Func 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; } } /// EF跟踪方式 删除 public async Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { _dbSet.Remove(entity); return await SaveChangesAsync(autoSave); } /// EF跟踪方式(查询出来,再删除 浪费性能,但是稽查 或者触发某些操作时,需要知道数据库实体信息 不可避免用这种) public async Task 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; } /// 批量删除,EF跟踪方式(所有查询出来,再删除 浪费性能,但是稽查 或者触发某些操作时,需要知道数据库实体信息 不可避免用这种) public async Task> DeleteFromQueryAsync(Expression> 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; } #endregion #region 不走EF 跟踪机制的删除 更新 以及批量操作 /// 批量删除,相当于原生sql, 没用EF跟踪方式(所有查询出来,再删除 浪费性能) public async Task BatchDeleteNoTrackingAsync(Expression> deleteFilter) { return await _dbSet.IgnoreQueryFilters().Where(deleteFilter).BatchDeleteAsync() > 0; } /// 批量更新,相当于原生sql, 没用EF跟踪方式(所有查询出来,再更新 浪费性能) public async Task BatchUpdateNoTrackingAsync(Expression> where, Expression> 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>(member, Expression.Parameter(typeof(TEntity), "x")); return await _dbSet.IgnoreQueryFilters().Where(where).BatchUpdateAsync(factory) > 0; } #endregion #region 保存 、忽略 、验证 public async Task InsertOrUpdateAsync(TFrom from, bool autoSave = false, params EntityVerifyExp[] verify) { var entity = _mapper.Map(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[] verify, Guid? entitydId = null) { if (isAdd) { 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); } } } else { foreach (var verifyItem in verify.Where(t => t.verifyType != VerifyEnum.OnlyAdd && t.IsVerify)) { if (verifyItem.verifyType == VerifyEnum.OnlyUpdate) { if (await _dbSet.IgnoreQueryFilters().AnyAsync(verifyItem.VerifyExp).ConfigureAwait(false)) { throw new BusinessValidationFailedException(verifyItem.VerifyMsg); } } else if (verifyItem.verifyType == VerifyEnum.Both) { if (await _dbSet.IgnoreQueryFilters().AnyAsync(verifyItem.VerifyExp.And(t => t.Id != entitydId)).ConfigureAwait(false)) { throw new BusinessValidationFailedException(verifyItem.VerifyMsg); } } } } } private async Task SaveChangesAsync(bool autoSave) { if (autoSave) { return await SaveChangesAsync(); } else { return false; } } /// /// 忽略空值属性 /// /// /// 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 SaveChangesAsync(CancellationToken cancellationToken = default) { return await _dbContext.SaveChangesAsync(cancellationToken) > 0; } #endregion #region 不常用 /// EF跟踪方式 生成 部分字段更新 (只更新传递的字段名 new[] {nameof(User.Name), nameof(User.Age)) public async Task UpdatePartialFieldsAsync(TEntity entity, string[] propertyNames, bool autoSave = false, bool ignoreEntityNullProperty = true, params EntityVerifyExp[] 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; } /// 更新 排除某些字段的更新 排除方式: new[] {nameof(User.Name), nameof(User.Age) public async Task UpdateExcludeFields(TEntity entity, string[] propertyNames, bool autoSave = false, bool ignoreEntityNullProperty = true, params EntityVerifyExp[] 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 稽查 ///// ///// ///// ///// ///// ///// //public async Task SetDictionaryValue(string Identification, string json) //{ //} ///// ///// ///// ///// ///// ///// ///// ///// //public async Task GetDictionaryValue(string Table,string ForeignKeyValue,string ForeignKeyText,string value) //{ // string para = string.Empty; // string sql = string.Empty; // string item = JsonConvert.SerializeObject(new { // item = value // }); // var JsonData = JsonConvert.DeserializeObject>(item); // if (JsonData["item"].GetType() == typeof(JArray)) // { // foreach (var v in JsonData["item"] as JArray) // { // para += para == string.Empty ? $"'{v}'" : $",'{v}'"; // } // } // else // { // } // //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.SqlQuery<> // //_dbContext.Database.ExecuteSqlRaw(strSql, para); //} /// /// 获取枚举 /// /// 标识 /// Json对象 /// /// public async Task SetEnum(Guid trilaid, string Identification, string json) { var list = await (from u in _dbContext.FrontAuditConfig.Where(x => x.Identification == Identification) join p in _dbContext.FrontAuditConfig.Where(x => x.Code != "AuditState" && (x.DictionaryCode != null && x.DictionaryCode != string.Empty && x.DictionaryType != null && x.DictionaryType != string.Empty)) 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 ? "AuditStateRC" : "AuditStatePE", Type = "Code", }); try { var JsonData = JsonConvert.DeserializeObject>(json); foreach (var item in list) { if (!JsonData.ContainsKey(item.Key)) { continue; } var value = JsonData[item.Key]; if (value.GetType() == typeof(JArray)) { JArray arrays = (JArray)value; if (item.Type.ToLower() == "id".ToLower()) { List guids = new List(); 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 guids = new List(); 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 guids = new List(); 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(); } } } return JsonConvert.SerializeObject(JsonData); } catch (Exception) { throw new BusinessValidationFailedException("Json 对象枚举异常"); } } private async Task AddInspectionAsync(TEntity entity, bool isSaveAudit = false) { List datas = new List(); var createtime = DateTime.Now.AddMilliseconds(200); // 项目 if (typeof(TEntity) == typeof(Trial)) { Trial data = entity as Trial; datas.Add(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() }); } // 受试者 if (typeof(TEntity) == typeof(Subject)) { Subject data = entity as Subject; datas.Add(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影像"); } // 修改访视状态记录稽查 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; } datas.Add(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(), }); } await AddListInspectionRecordAsync(datas); } /// /// 添加稽查记录 /// /// /// public async Task AddListInspectionRecordAsync(List 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); } /// /// IsNullOrEmpty /// /// /// private bool IsNullOrEmpty(object value) { if (value == null || value.ToString() == string.Empty) { return true; } else { return false; } } /// /// 格式化日期和时间 /// /// /// public async Task 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.DateType != null && x.DateType != string.Empty) on parent.Id equals child.ParentId select new DateDto() { Code = child.Code, DateType = child.DateType, }).ToListAsync(); var JsonData = JsonConvert.DeserializeObject>(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; } /// /// 设置项目以及名称 /// /// /// 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 } #endregion #region 异步查询 public async Task MaxAsync(Expression> selector) { return await _dbSet.AsNoTracking().MaxAsync(selector); } public async Task AnyAsync(Expression> exp, bool ignoreQueryFilters = false) { var query = _dbSet.AsQueryable(); if (ignoreQueryFilters) { query = query.IgnoreQueryFilters(); } return await query.AsNoTracking().AnyAsync(exp); } public async Task CountAsync(Expression> 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 FindAsync(Guid id, CancellationToken cancellationToken = default) { return await _dbContext.FindAsync(id); } //有可能是联合主键,本项目没用到,用Guid public async ValueTask FindAsync(object[] keyValues, CancellationToken cancellationToken) { return await _dbContext.FindAsync(keyValues); } public async Task FirstOrDefaultAsync(Expression> exp = null, bool ignoreQueryFilters = false) { var query = _dbSet.AsQueryable(); if (ignoreQueryFilters) { query = query.IgnoreQueryFilters(); } if (exp == null) return await query.FirstOrDefaultAsync().ConfigureAwait(false); return await query.FirstOrDefaultAsync(exp).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 AsQueryable(bool ignoreQueryFilters = false) { var query = _dbSet.AsQueryable(); if (ignoreQueryFilters) { query = query.IgnoreQueryFilters(); } return query.AsNoTracking(); } public IQueryable Select(Expression> selector) { return _dbSet.AsNoTracking().Select(selector); } public IQueryable WhereIf(bool condition, Expression> filter) { return condition ? _dbSet.AsNoTracking().Where(filter) : _dbSet.AsNoTracking(); } public IQueryable Where(Expression> exp = null, bool isTraking = false, bool ignoreQueryFilters = false) { IQueryable 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 Attach(TEntity entity) { return _dbSet.Attach(entity); } public void Detached(TEntity t) { _dbContext.Entry(t).State = EntityState.Detached; } // automapper 相关 public IQueryable ProjectTo(IConfigurationProvider configuration, object parameters, params Expression>[] membersToExpand) { return _dbSet.AsNoTracking().ProjectTo(configuration, parameters, membersToExpand); } public IQueryable ProjectTo(IConfigurationProvider configuration, params Expression>[] membersToExpand) { return _dbSet.AsNoTracking().ProjectTo(configuration, membersToExpand); } public IQueryable ProjectTo(IConfigurationProvider configuration, IDictionary parameters, params string[] membersToExpand) { return _dbSet.AsNoTracking().ProjectTo(configuration, parameters, membersToExpand); } #endregion #region 待废弃 /// /// 仅仅供字典表插入使用,因为efcore 动态映射列的问题 /// /// /// /// /// /// public async Task InsertDictionaryAsync(TFrom from, params EntityVerifyExp[] verify) { var entity = _mapper.Map(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() { entity }); //return entity; } } public async Task AddRangeAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default) { await _dbSet.AddRangeAsync(entities).ConfigureAwait(false); if (autoSave) { return await SaveChangesAsync(cancellationToken); } else { return false; } } #endregion } }