diff --git a/IRaCIS.Core.API/Progranm.cs b/IRaCIS.Core.API/Progranm.cs index 69be6d74f..a3b23aa44 100644 --- a/IRaCIS.Core.API/Progranm.cs +++ b/IRaCIS.Core.API/Progranm.cs @@ -96,6 +96,12 @@ builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resourc // 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim() builder.Services.AddControllers(options => { + // 关键配置:禁用不可空引用类型的自动 Required 验证 + options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true; + + // 插到最前,抢在默认绑定器之前 + //options.ModelBinderProviders.Insert(0, new SpecificNullableBinderProvider()); + options.Filters.Add(); options.Filters.Add(); options.Filters.Add(); diff --git a/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/JSONTimeZoneConverter.cs b/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/JSONTimeZoneConverter.cs index 9b289e8a4..16e4155c4 100644 --- a/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/JSONTimeZoneConverter.cs +++ b/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/JSONTimeZoneConverter.cs @@ -71,29 +71,27 @@ namespace IRaCIS.Core.API DateTime dateTime; - if (reader.ValueType == typeof(DateTime) || reader.ValueType == typeof(DateTime?)) + // 2. 检查目标类型是否可空 + bool isNullable = objectType == typeof(DateTime?); + + var canConvert = DateTime.TryParse(reader.Value?.ToString(), out dateTime); + + + if (isNullable == false && canConvert == false) { - DateTime? nullableDateTime = reader.Value as DateTime?; - - if (nullableDateTime != null && nullableDateTime.HasValue) - { - dateTime = nullableDateTime.Value; - } - else - { - return null; - } + throw new JsonSerializationException($"Could not convert string to DateTime: {reader.Value} Path {reader.Path}"); } else { - if (DateTime.TryParse((string)reader.Value, out dateTime) == false) + if (canConvert == false) { return null; } } - + ////如果前端传递带时区的,那么转换会报错,需要DateTimeKind.Unspecified + //dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified); // 将客户端时间转换为服务器时区的时间 var serverZoneTime = TimeZoneInfo.ConvertTime(dateTime, _clientTimeZone, TimeZoneInfo.Local); @@ -113,7 +111,10 @@ namespace IRaCIS.Core.API //第一个参数默认使用系统本地时区 也就是应用服务器的时区 DateTime clientZoneTime = TimeZoneInfo.ConvertTime(nullableDateTime.Value, _clientTimeZone); - //writer.WriteValue(clientZoneTime); + + //// 最简单的方式:创建 DateTimeOffset + //DateTimeOffset dateTimeOffset = new DateTimeOffset(clientZoneTime, _clientTimeZone.GetUtcOffset(clientZoneTime)); + //writer.WriteValue(dateTimeOffset.ToString("yyyy-MM-dd HH:mm:sszzz")); writer.WriteValue(clientZoneTime.ToString(_dateFormat)); } diff --git a/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/NullToEmptyStringResolver.cs b/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/NullToEmptyStringResolver.cs index 04bb3a2c0..146bdf25d 100644 --- a/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/NullToEmptyStringResolver.cs +++ b/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/NullToEmptyStringResolver.cs @@ -3,8 +3,10 @@ using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; +using System.Reflection.Metadata; namespace IRaCIS.Core.API { @@ -51,34 +53,90 @@ namespace IRaCIS.Core.API } public class NullToEmptyStringValueProvider : IValueProvider { - PropertyInfo _MemberInfo; + PropertyInfo _memberInfo; + private readonly bool _isNullable; public NullToEmptyStringValueProvider(PropertyInfo memberInfo) { - _MemberInfo = memberInfo; + _memberInfo = memberInfo; + } + + + + // DTO → JSON 返回前端的时候 处理null 变为"" 方便前端判断 public object GetValue(object target) { - object result = _MemberInfo.GetValue(target); - if (_MemberInfo.PropertyType == typeof(string) && result == null) result = ""; - else if (_MemberInfo.PropertyType == typeof(String[]) && result == null) result = new string[] { }; - //else if (_MemberInfo.PropertyType == typeof(Nullable) && result == null) result = 0; - //else if (_MemberInfo.PropertyType == typeof(Nullable) && result == null) result = 0.00M; + var result = _memberInfo.GetValue(target); + // 检查类型是否为string或string? + if (_memberInfo.PropertyType == typeof(string) && result == null) + { + #region 返回的时候处理 string string? null 为"" 不区分处理 + + + //// 如果是string?类型,返回null 可以做到,但是得反射,因为 string string? 是编译层区分的 + + //var isNullable1 = _memberInfo.CustomAttributes + // .Any(a => a.AttributeType.Name == "NullableAttribute"); + + ////var isNullable2 = _memberInfo.CustomAttributes + //// .Any(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute"); + + //if (isNullable1) + //{ + // return result; + //} + + #endregion + + + // 如果是string类型,返回空字符串 + return string.Empty; + } return result; } + + + //影响 模型绑定时接收前端的值,同时影响 正常 JSON 序列化 public void SetValue(object target, object value) { - if (_MemberInfo.PropertyType == typeof(string)) - { - //去掉前后空格 - _MemberInfo.SetValue(target, value == null ? string.Empty : value.ToString() == string.Empty ? value : value/*.ToString().Trim()*/); + _memberInfo.SetValue(target, value); + + #region 前端针对 string 类型的变量,如果传递null 会报错必传 + + //if (_memberInfo.PropertyType == typeof(string)) + //{ + // _memberInfo.SetValue(target, value == null ? string.Empty : value); + //} + //else + //{ + // _memberInfo.SetValue(target, value); + //} + + #endregion + + #region 处理模型验证区分 string string? + + //////接收模型的时候 定义的明明是string 但是上面也有该属性,判断不准的 比如阅片跟踪列表查询 + //var isNullable1 = _memberInfo.CustomAttributes.Any(a => a.AttributeType.Name == "NullableAttribute"); + + ////不影响 string? 传递null 变为"" + //if (_memberInfo.PropertyType == typeof(string) && isNullable1 == false) + //{ + // //如果不处理 前段传递null string不会接收,说前段没传递会验证报错 + // _memberInfo.SetValue(target, value == null ? string.Empty : value); + //} + //else + //{ + + // _memberInfo.SetValue(target, value); + + //} + + #endregion + - } - else - { - _MemberInfo.SetValue(target, value); - } } } diff --git a/IRaCIS.Core.Application/BusinessFilter/LegacyController/ModelActionFilter .cs b/IRaCIS.Core.Application/BusinessFilter/LegacyController/ModelActionFilter .cs index 63255f4fa..ee1d392cf 100644 --- a/IRaCIS.Core.Application/BusinessFilter/LegacyController/ModelActionFilter .cs +++ b/IRaCIS.Core.Application/BusinessFilter/LegacyController/ModelActionFilter .cs @@ -1,7 +1,11 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; +using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; using Microsoft.Extensions.Localization; using Newtonsoft.Json; +using System.Reflection; namespace IRaCIS.Core.Application.Filter; @@ -28,3 +32,7 @@ public class ModelActionFilter(IStringLocalizer _localizer) : ActionFilterAttrib } } } + + + + diff --git a/IRaCIS.Core.Application/Helper/DicomDIRHelper.cs b/IRaCIS.Core.Application/Helper/DicomDIRHelper.cs index 44f71203b..12c387440 100644 --- a/IRaCIS.Core.Application/Helper/DicomDIRHelper.cs +++ b/IRaCIS.Core.Application/Helper/DicomDIRHelper.cs @@ -1,4 +1,5 @@ -using FellowOakDicom; +using DocumentFormat.OpenXml.Office.CustomUI; +using FellowOakDicom; using FellowOakDicom.Media; using System; using System.Collections.Generic; @@ -57,6 +58,7 @@ namespace IRaCIS.Core.Application.Helper var mappings = new List(); int index = 1; + var studyUid=list.FirstOrDefault()?.StudyInstanceUid; var dicomDir = new DicomDirectory(); @@ -130,7 +132,7 @@ namespace IRaCIS.Core.Application.Helper var relativePath= await _oSSService.UploadToOSSAsync(memoryStream, ossFolder, "DICOMDIR", true); - dic.Add("DICOMDIR" , relativePath.Split('/').Last()); + dic.Add($"{studyUid}_DICOMDIR" , relativePath.Split('/').Last()); } //清理临时文件 diff --git a/IRaCIS.Core.Application/Service/Allocation/VisitTaskService.cs b/IRaCIS.Core.Application/Service/Allocation/VisitTaskService.cs index 2537cbd5e..e6e02aeb1 100644 --- a/IRaCIS.Core.Application/Service/Allocation/VisitTaskService.cs +++ b/IRaCIS.Core.Application/Service/Allocation/VisitTaskService.cs @@ -1173,7 +1173,7 @@ public class VisitTaskService(IRepository _visitTaskRepository, var visitQuery = _visitTaskRepository.Where(x => x.TrialId == trialId && x.DoctorUserId == _userInfo.UserRoleId && x.TaskState == TaskState.Effect) .WhereIf(inQuery.SubjectId != null, x => x.SubjectId == inQuery.SubjectId) .WhereIf(!string.IsNullOrEmpty(subjectCode), t => (t.Subject.Code.Contains(subjectCode!) && t.IsAnalysisCreate == false) || (t.BlindSubjectCode.Contains(subjectCode!) && t.IsAnalysisCreate)) - .WhereIf(critrion.CriterionType == CriterionType.OCT, t => t.ReadingCategory == ReadingCategory.Visit ? t.SourceSubjectVisit.NoneDicomStudyList.Where(t=>t.Modality=="OCT").SelectMany(t => t.ImageLabelNoneDicomFileList).Any() : true) + .WhereIf(critrion.CriterionType == CriterionType.OCT, t => t.ReadingCategory == ReadingCategory.Visit ? t.SourceSubjectVisit.NoneDicomStudyList.Where(t => t.Modality == "OCT").SelectMany(t => t.ImageLabelNoneDicomFileList).Any() : true) .WhereIf(critrion.CriterionType == CriterionType.IVUS, t => t.ReadingCategory == ReadingCategory.Visit ? t.SourceSubjectVisit.NoneDicomStudyList.Where(t => t.Modality == "IVUS").SelectMany(t => t.ImageLabelNoneDicomFileList).Any() : true); var visitGroupQuery = visitQuery.GroupBy(x => new { x.SubjectId, x.Subject.Code, x.BlindSubjectCode }); @@ -2293,12 +2293,12 @@ public class VisitTaskService(IRepository _visitTaskRepository, foreach (var item in readingTableAnswerRowInfoList) { - if (item.SplitRowId!=null&&lesionRelationship.ContainsKey(item.SplitRowId.Value)) + if (item.SplitRowId != null && lesionRelationship.ContainsKey(item.SplitRowId.Value)) { item.SplitRowId = lesionRelationship[item.SplitRowId.Value]; } - if (item.MergeRowId!=null&&lesionRelationship.ContainsKey(item.MergeRowId.Value)) + if (item.MergeRowId != null && lesionRelationship.ContainsKey(item.MergeRowId.Value)) { item.MergeRowId = lesionRelationship[item.MergeRowId.Value]; } @@ -2403,6 +2403,10 @@ public class VisitTaskService(IRepository _visitTaskRepository, //另一个阅片人的任务根据任务进度自动进入PM退回或PM申请重阅 filterExpression = filterExpression.And(t => t.VisitTaskNum >= task.VisitTaskNum); + //退回只影响有序的后续所有的,无序的当前访视 + filterExpression = filterExpression.And(t => (t.TrialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.InOrder) || + (t.TrialReadingCriterion.IsReadingTaskViewInOrder != ReadingOrder.InOrder && t.SourceSubjectVisitId == task.SourceSubjectVisitId)); + var influenceTaskList = await _visitTaskRepository.Where(filterExpression, true).ToListAsync(); @@ -2564,7 +2568,7 @@ public class VisitTaskService(IRepository _visitTaskRepository, otherVisitIdList = otherVisitIdList.Where(t => t != task.SourceSubjectVisitId.Value).ToList(); } - + //BM后续访视 ,筛选状态不变,任务生成状态重置(实际该访视任务状态 可能是重阅重置了或者失效了,需要后续生成,或者取消分配了,需要后续重新分配) await _subjectCriteriaEvaluationVisitFilterRepository.UpdatePartialFromQueryAsync(t => t.TrialReadingCriterion.CriterionType == CriterionType.RECIST1Pointt1_MB && t.SubjectVisit.SubjectId == task.SubjectId && otherVisitIdList.Contains(t.SubjectVisitId), @@ -2727,6 +2731,13 @@ public class VisitTaskService(IRepository _visitTaskRepository, //默认影响的都是该标准的任务 filterExpression = filterExpression.And(t => t.TrialReadingCriterionId == filterObj.TrialReadingCriterionId); } + + //退回只影响有序的后续所有的,无序的当前访视 + if (isReReading == false) + { + filterExpression = filterExpression.And(t => (t.TrialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.InOrder) || + (t.TrialReadingCriterion.IsReadingTaskViewInOrder != ReadingOrder.InOrder && t.SourceSubjectVisitId == filterObj.SourceSubjectVisitId)); + } } diff --git a/IRaCIS.Core.Application/Service/Common/Export/TumorExportService.cs b/IRaCIS.Core.Application/Service/Common/Export/TumorExportService.cs index f08d03e6c..214fae7bb 100644 --- a/IRaCIS.Core.Application/Service/Common/Export/TumorExportService.cs +++ b/IRaCIS.Core.Application/Service/Common/Export/TumorExportService.cs @@ -601,9 +601,11 @@ public class Tumor_CDISC_ExportService(IRepository t.SubjectCode == task.SubjectCode && t.ARM_TumorNo == $"{task.ArmEnumStr}_{lesion.LessionCode}")) { - var tu = CreatNewTUExport(task, lesion, visitIndexNoDic, translateDataList, isEn_Us); if (lesion.OrganInfoId.HasValue) { diff --git a/IRaCIS.Core.Application/Service/Document/DTO/SystemDocumentViewModel.cs b/IRaCIS.Core.Application/Service/Document/DTO/SystemDocumentViewModel.cs index a0b89b912..e7ce1734a 100644 --- a/IRaCIS.Core.Application/Service/Document/DTO/SystemDocumentViewModel.cs +++ b/IRaCIS.Core.Application/Service/Document/DTO/SystemDocumentViewModel.cs @@ -92,6 +92,10 @@ namespace IRaCIS.Core.Application.Contracts public class UnionDocumentWithConfirmInfoView : UnionDocumentView { + public DocUserSignType SysDocUserSignType { get; set; } + + public bool IsConfirmIdentityUserInner { get; set; } + public Guid TrialId { get; set; } public bool IsNeedSendEmial { get; set; } diff --git a/IRaCIS.Core.Application/Service/Document/Interface/ITrialDocumentService.cs b/IRaCIS.Core.Application/Service/Document/Interface/ITrialDocumentService.cs index e2ed0597b..d83a287ac 100644 --- a/IRaCIS.Core.Application/Service/Document/Interface/ITrialDocumentService.cs +++ b/IRaCIS.Core.Application/Service/Document/Interface/ITrialDocumentService.cs @@ -19,6 +19,8 @@ namespace IRaCIS.Core.Application.Contracts Task UserConfirm(UserConfirmCommand userConfirmCommand); Task> GetTrialUserSelect(Guid trialId); + Task>> GetSysDocumentConfirmList(SystemDocQuery inQuery); + //Task> GetTrialSystemDocumentList(DocumentTrialUnionQuery querySystemDocument); //List GetTrialUserDocumentList(Guid trialId); diff --git a/IRaCIS.Core.Application/Service/Document/SystemDocumentService.cs b/IRaCIS.Core.Application/Service/Document/SystemDocumentService.cs index e934d2864..e279c8f91 100644 --- a/IRaCIS.Core.Application/Service/Document/SystemDocumentService.cs +++ b/IRaCIS.Core.Application/Service/Document/SystemDocumentService.cs @@ -302,6 +302,7 @@ namespace IRaCIS.Core.Application.Services { AttachmentCount=sysDoc.SystemDocumentAttachmentList.Where(z=>!z.OffLine).Count(), IsSystemDoc = true, + IsPublish=sysDoc.IsPublish, CurrentStaffTrainDays=sysDoc.CurrentStaffTrainDays, NewStaffTrainDays = sysDoc.NewStaffTrainDays, Id = sysDoc.Id, @@ -327,6 +328,7 @@ namespace IRaCIS.Core.Application.Services //UserTypeShortName = user.UserTypeRole.UserTypeShortName }; + var list = await query //过滤掉删除的,并且没有签名的 .Where(t => !(t.IsDeleted == true && t.ConfirmTime == null)) diff --git a/IRaCIS.Core.Application/Service/Document/TrialDocumentService.cs b/IRaCIS.Core.Application/Service/Document/TrialDocumentService.cs index 59c4f2c4c..ef14f4cfb 100644 --- a/IRaCIS.Core.Application/Service/Document/TrialDocumentService.cs +++ b/IRaCIS.Core.Application/Service/Document/TrialDocumentService.cs @@ -952,10 +952,13 @@ namespace IRaCIS.Core.Application.Services return ResponseOutput.Ok(new PageOutput()); } + var systemDocQuery = - from sysDoc in _systemDocumentRepository.AsQueryable(false) + from sysDoc in _systemDocumentRepository.Where(t => t.IsPublish) .Where(t => inQuery.UserTypeId != null ? t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == inQuery.UserTypeId) : true) - from identityUser in _identityUserRepository.AsQueryable(false).Where(t => t.Status == UserStateEnum.Enable && t.UserRoleList.Where(t => t.IsUserRoleDisabled == false).Any(t => sysDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId))) + from identityUser in _identityUserRepository.AsQueryable(false) + + .Where(t => t.Status == UserStateEnum.Enable && t.UserRoleList.Where(t => t.IsUserRoleDisabled == false).Any(t => sysDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId))) .Where(t => inQuery.UserId != null ? t.Id == inQuery.UserId : true) .Where(t => inQuery.UserTypeId != null ? t.UserRoleList.Any(t => t.UserTypeId == inQuery.UserTypeId && t.IsUserRoleDisabled == false) : true) .Where(t => isEA ? t.IsZhiZhun == true : true) //EA 只能查看内部人员文档 @@ -964,6 +967,9 @@ namespace IRaCIS.Core.Application.Services select new UnionDocumentWithConfirmInfoView() { IsSystemDoc = true, + SysDocUserSignType = sysDoc.DocUserSignType, + IsConfirmIdentityUserInner = identityUser.IsZhiZhun, + IsPublish=sysDoc.IsPublish, Id = sysDoc.Id, CreateTime = sysDoc.CreateTime, IsDeleted = sysDoc.IsDeleted, @@ -995,14 +1001,16 @@ namespace IRaCIS.Core.Application.Services }; var unionQuery = systemDocQuery.IgnoreQueryFilters().Where(t => !(t.IsDeleted == true && t.ConfirmTime == null)) + //外部人员 只签署 外部需要签署的 + .Where(t => t.IsConfirmIdentityUserInner == false ? t.SysDocUserSignType == DocUserSignType.InnerAndOuter : true) .WhereIf(!string.IsNullOrEmpty(inQuery.Name), t => t.Name.Contains(inQuery.Name)) .WhereIf(inQuery.FileTypeId != null, t => t.FileTypeId == inQuery.FileTypeId) .WhereIf(inQuery.IsConfirmed == true, t => t.ConfirmTime != null) .WhereIf(inQuery.IsConfirmed == false, t => t.ConfirmTime == null) .WhereIf(inQuery.StartConfirmTime != null, t => t.ConfirmTime >= inQuery.StartConfirmTime.Value) .WhereIf(inQuery.EndConfirmTime != null, t => t.ConfirmTime <= inQuery.EndConfirmTime.Value) - .WhereIf(inQuery.BeginCreateTime != null, t => t.CreateTime >= inQuery.BeginCreateTime) - .WhereIf(inQuery.EndCreateTime != null, t => t.CreateTime <= inQuery.EndCreateTime) + .WhereIf(inQuery.BeginCreateTime != null, t => t.CreateTime >= inQuery.BeginCreateTime) + .WhereIf(inQuery.EndCreateTime != null, t => t.CreateTime <= inQuery.EndCreateTime) .WhereIf(!string.IsNullOrEmpty(inQuery.UserName), t => t.UserName.Contains(inQuery.UserName)) .WhereIf(inQuery.IsDeleted != null, t => t.IsDeleted == inQuery.IsDeleted) .WhereIf(isInternal == false, t => t.ConfirmTime != null); //不是内部的人,看有签名时间的 diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs index 2dad6b397..4491fb6fe 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs @@ -1185,6 +1185,9 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc foreach (var item in list.GroupBy(t => new { t.StudyInstanceUid, t.DicomStudyId })) { + + var studyUid = item.Key.StudyInstanceUid; + var ossFolder = $"{pathInfo.TrialId}/Image/{pathInfo.SubjectId}/{pathInfo.VisitId}/{item.Key.StudyInstanceUid}"; var isSucess = await SafeBussinessHelper.RunAsync(async () => await DicomDIRHelper.GenerateStudyDIRAndUploadAsync(item.ToList(), dirDic, ossFolder, _oSSService)); @@ -1192,7 +1195,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc if (isSucess) { - await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic["DICOMDIR"]}" }); + await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic[$"{studyUid}_DICOMDIR"]}" }); } } @@ -1625,6 +1628,8 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc var ossFolder = $"{pathInfo.TrialId}/Image/{pathInfo.SubjectId}/{visitId}/{item.Key.StudyInstanceUid}"; + var studyUid = item.Key.StudyInstanceUid; + var isSucess = await SafeBussinessHelper.RunAsync(async () => await DicomDIRHelper.GenerateStudyDIRAndUploadAsync(item.ToList(), dirDic, ossFolder, _oSSService)); @@ -1632,11 +1637,11 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc { if (isTaskStudy) { - await _taskStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new TaskStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic["DICOMDIR"]}" }); + await _taskStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new TaskStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic[$"{studyUid}_DICOMDIR"]}" }); } else { - await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic["DICOMDIR"]}" }); + await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic[$"{studyUid}_DICOMDIR"]}" }); } } @@ -2303,6 +2308,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc var subjectId = item.First().SubjectId; + var studyUid = item.Key.StudyInstanceUid; var ossFolder = $"{inCommand.TrialId}/Image/{subjectId}/{visitId}/{item.Key.StudyInstanceUid}"; @@ -2310,7 +2316,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc if (isSucess) { - await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic["DICOMDIR"]}" }); + await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic[$"{studyUid}_DICOMDIR"]}" }); } } } diff --git a/IRaCIS.Core.Application/TestService.cs b/IRaCIS.Core.Application/TestService.cs index fd751a860..ecb3badd6 100644 --- a/IRaCIS.Core.Application/TestService.cs +++ b/IRaCIS.Core.Application/TestService.cs @@ -39,6 +39,7 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Processing; using System.Collections.Concurrent; +using System.ComponentModel.DataAnnotations; using System.Diagnostics; using System.Globalization; using System.IO; @@ -77,6 +78,46 @@ namespace IRaCIS.Core.Application.Service public static int IntValue = 100; + public class ModelVerifyCommand + { + public int? IntNUllValue { get; set; } + public int IntValue { get; set; } + + public string StringValue { get; set; } + + public string? StringNUllValue { get; set; } + + public string StringBackDefaultValue { get; set; } = string.Empty; + + public Guid GuidValue { get; set; } = NewId.NextSequentialGuid(); + + public Guid? GuidNUllValue { get; set; } + + [NotDefault] + public Guid GuidValueNotDefault { get; set; } + + + public bool BoolValue { get; set; } + + public bool? BoolNUllValue { get; set; } + + public DateTime DateTimeValue { get; set; } + + public DateTime? DateTimeNUllValue { get; set; } + } + + + //创建一个模型验证的方法 + [AllowAnonymous] + [HttpPost] + public async Task PostModelVerify(ModelVerifyCommand modelVerify) + { + + return ResponseOutput.Ok(modelVerify); + + } + + [AllowAnonymous] public async Task CreatNewDBStruct() @@ -99,10 +140,10 @@ namespace IRaCIS.Core.Application.Service public async Task DeleteCacheDIR() { - var list= _dicomStudyRepository.Where(t => t.StudyDIRPath!="").Select(t => t.StudyDIRPath).ToList(); + var list = _dicomStudyRepository.Where(t => t.StudyDIRPath != "").Select(t => t.StudyDIRPath).ToList(); - await _IOSSService.DeleteObjects(list.Select(t => t.TrimStart('/')).ToList(),true); + await _IOSSService.DeleteObjects(list.Select(t => t.TrimStart('/')).ToList(), true); return ResponseOutput.Ok(); } diff --git a/IRaCIS.Core.Infra.EFCore/Repository/IRaCISContextExtension.cs b/IRaCIS.Core.Infra.EFCore/Repository/IRaCISContextExtension.cs index 71fb563e1..ebd59fe2a 100644 --- a/IRaCIS.Core.Infra.EFCore/Repository/IRaCISContextExtension.cs +++ b/IRaCIS.Core.Infra.EFCore/Repository/IRaCISContextExtension.cs @@ -119,7 +119,10 @@ namespace IRaCIS.Core.Infra.EFCore /// EntityState.Detached的实体 修改 部分字段 public static void EntityModifyPartialFiled(this IRaCISDBContext _dbContext, T waitModifyEntity, Expression> updateFactory) where T : Entity { - var entityEntry = _dbContext.Entry(waitModifyEntity); + //解决重复跟踪问题 + var tracked = _dbContext.ChangeTracker.Entries().FirstOrDefault(e => e.Entity.Id.Equals(waitModifyEntity.Id)); + var entityEntry = tracked?? _dbContext.Entry(waitModifyEntity); + //entityEntry.State = EntityState.Detached; var list = ((MemberInitExpression)updateFactory.Body).Bindings.Select(mb => mb.Member.Name) @@ -134,7 +137,7 @@ namespace IRaCIS.Core.Infra.EFCore foreach (PropertyInfo prop in list) { - _dbContext.Entry(waitModifyEntity).Property(prop.Name).IsModified = true; + entityEntry.Property(prop.Name).IsModified = true; object value = prop.GetValue(applyObj); prop.SetValue(waitModifyEntity, value);