diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 000000000..20558076c --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,9 @@ + + + + net10.0 + + enable + enable + + \ No newline at end of file diff --git a/IRC.Core.Dicom/IRC.Core.Dicom.csproj b/IRC.Core.Dicom/IRC.Core.Dicom.csproj index 3a9fd6fda..c25ddc765 100644 --- a/IRC.Core.Dicom/IRC.Core.Dicom.csproj +++ b/IRC.Core.Dicom/IRC.Core.Dicom.csproj @@ -1,37 +1,36 @@ - net8.0 - enable + enable - + - - + + - - + + - - - - - - - - - + + + + + + + + + true - - - - - + + + + + diff --git a/IRC.Core.Dicom/Program.cs b/IRC.Core.Dicom/Program.cs index 924632fd8..bddd45558 100644 --- a/IRC.Core.Dicom/Program.cs +++ b/IRC.Core.Dicom/Program.cs @@ -56,7 +56,7 @@ var _configuration = builder.Configuration; builder.Services.AddHealthChecks(); //ػ -builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resources"); +builder.Services.AddJsonLocalization(options => options.ResourcesPath = new[] { "Resources" }); // 쳣ͳһ֤JsonлáַͳһTrim() diff --git a/IRC.Core.SCP/IRC.Core.SCP.csproj b/IRC.Core.SCP/IRC.Core.SCP.csproj index b44373939..e5336e6c9 100644 --- a/IRC.Core.SCP/IRC.Core.SCP.csproj +++ b/IRC.Core.SCP/IRC.Core.SCP.csproj @@ -1,8 +1,6 @@  - net8.0 - enable enable @@ -10,17 +8,17 @@ - - + + - + - + true diff --git a/IRC.Core.SCP/Program.cs b/IRC.Core.SCP/Program.cs index db4c1450e..9b9d66b2d 100644 --- a/IRC.Core.SCP/Program.cs +++ b/IRC.Core.SCP/Program.cs @@ -13,7 +13,6 @@ using IRaCIS.Core.SCP.Service; using MassTransit; using MassTransit.NewIdProviders; using Microsoft.AspNetCore.HttpOverrides; -using Microsoft.Extensions.DependencyInjection; using Panda.DynamicWebApi; using Serilog; using Serilog.Events; @@ -71,7 +70,7 @@ builder.Services.AddHostedService(); builder.Services.AddHealthChecks(); //本地化 -builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resources"); +builder.Services.AddJsonLocalization(options => options.ResourcesPath = new[] { "Resources" }); // 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim() diff --git a/IRaCIS.Core.API/Controllers/ExtraController.cs b/IRaCIS.Core.API/Controllers/ExtraController.cs index d6fabd6c8..b98d9a036 100644 --- a/IRaCIS.Core.API/Controllers/ExtraController.cs +++ b/IRaCIS.Core.API/Controllers/ExtraController.cs @@ -1,43 +1,21 @@ using AlibabaCloud.SDK.Sts20150401; -using Amazon.Auth.AccessControlPolicy; using Amazon.SecurityToken; -using AutoMapper; -using Azure.Core; -using IdentityModel.Client; -using IdentityModel.OidcClient; using IRaCIS.Application.Contracts; using IRaCIS.Application.Interfaces; using IRaCIS.Core.Application.Auth; -using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Helper; -using IRaCIS.Core.Application.Service; using IRaCIS.Core.Domain.Models; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infra.EFCore; using IRaCIS.Core.Infrastructure.Extention; using MassTransit; -using MassTransit.Futures.Contracts; using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Org.BouncyCastle.Tls; -using RestSharp; -using RestSharp.Authenticators; using Serilog; -using System; -using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Net; -using System.Net.Http; using System.Text; -using System.Text.Json; -using System.Threading.Tasks; -using ZiggyCreatures.Caching.Fusion; using AssumeRoleRequest = Amazon.SecurityToken.Model.AssumeRoleRequest; -using LoginReturnDTO = IRaCIS.Application.Contracts.LoginReturnDTO; namespace IRaCIS.Api.Controllers { diff --git a/IRaCIS.Core.API/Controllers/UploadDownLoadController.cs b/IRaCIS.Core.API/Controllers/UploadDownLoadController.cs index 45fe63600..ea15e396d 100644 --- a/IRaCIS.Core.API/Controllers/UploadDownLoadController.cs +++ b/IRaCIS.Core.API/Controllers/UploadDownLoadController.cs @@ -1,11 +1,9 @@ using AutoMapper; using ExcelDataReader; -using IRaCIS.Application.Interfaces; using IRaCIS.Core.Application.BusinessFilter; using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Contracts.Dicom; using IRaCIS.Core.Application.Contracts.Dicom.DTO; -using IRaCIS.Core.Application.Filter; using IRaCIS.Core.Application.Helper; using IRaCIS.Core.Application.MassTransit.Command; using IRaCIS.Core.Application.Service; @@ -17,8 +15,6 @@ using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Infrastructure.Extention; using MassTransit.Mediator; using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.ModelBinding; @@ -27,21 +23,15 @@ using Microsoft.AspNetCore.StaticFiles; using Microsoft.AspNetCore.WebUtilities; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Localization; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Net.Http.Headers; using MiniExcelLibs; using Newtonsoft.Json; using SharpCompress.Archives; -using System; -using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Data; -using System.IO; -using System.Linq; using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; using Path = System.IO.Path; namespace IRaCIS.Core.API.Controllers @@ -132,7 +122,7 @@ namespace IRaCIS.Core.API.Controllers //处理压缩文件 if (fileName.Contains(".Zip", StringComparison.OrdinalIgnoreCase) || fileName.Contains(".rar", StringComparison.OrdinalIgnoreCase)) { - var archive = ArchiveFactory.Open(section.Body); + var archive = ArchiveFactory.OpenArchive(section.Body); foreach (var entry in archive.Entries) { @@ -213,7 +203,7 @@ namespace IRaCIS.Core.API.Controllers //处理压缩文件 if (fileName.Contains(".Zip", StringComparison.OrdinalIgnoreCase) || fileName.Contains(".rar", StringComparison.OrdinalIgnoreCase)) { - var archive = ArchiveFactory.Open(section.Body); + var archive = ArchiveFactory.OpenArchive(section.Body); foreach (var entry in archive.Entries) { diff --git a/IRaCIS.Core.API/IRaCIS.Core.API.csproj b/IRaCIS.Core.API/IRaCIS.Core.API.csproj index 9361510e9..3a1be9e74 100644 --- a/IRaCIS.Core.API/IRaCIS.Core.API.csproj +++ b/IRaCIS.Core.API/IRaCIS.Core.API.csproj @@ -1,7 +1,6 @@  - net8.0 false 354572d4-9e15-4099-807c-63a2d29ff9f2 default @@ -69,22 +68,22 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + - + - + diff --git a/IRaCIS.Core.API/IRaCIS.Core.API.xml b/IRaCIS.Core.API/IRaCIS.Core.API.xml index bdefda92d..2566f292e 100644 --- a/IRaCIS.Core.API/IRaCIS.Core.API.xml +++ b/IRaCIS.Core.API/IRaCIS.Core.API.xml @@ -378,6 +378,11 @@ LowerCamelCaseJsonAttribute 可以设置类小写返回给前端 + + + Auto-generated public partial Program class for top-level statement apps. + + 对称可逆加密 @@ -413,5 +418,49 @@ + + + Generates a documentation comment ID for a type. + Example: T:Namespace.Outer+Inner`1 becomes T:Namespace.Outer.Inner`1 + + + + + Generates a documentation comment ID for a property. + Example: P:Namespace.ContainingType.PropertyName or for an indexer P:Namespace.ContainingType.Item(System.Int32) + + + + + Generates a documentation comment ID for a property given its container type and property name. + Example: P:Namespace.ContainingType.PropertyName + + + + + Generates a documentation comment ID for a method (or constructor). + For example: + M:Namespace.ContainingType.MethodName(ParamType1,ParamType2)~ReturnType + M:Namespace.ContainingType.#ctor(ParamType) + + + + + Generates a documentation ID string for a type. + This method handles nested types (replacing '+' with '.'), + generic types, arrays, pointers, by-ref types, and generic parameters. + The flag controls whether + constructed generic type arguments are emitted, while + controls whether the generic arity marker (e.g. "`1") is appended. + + + + + Normalizes a documentation comment ID to match the compiler-style format. + Strips the return type suffix for ordinary methods but retains it for conversion operators. + + The documentation comment ID to normalize. + The normalized documentation comment ID. + diff --git a/IRaCIS.Core.API/Progranm.cs b/IRaCIS.Core.API/Progranm.cs index 362f88c60..d01a1699b 100644 --- a/IRaCIS.Core.API/Progranm.cs +++ b/IRaCIS.Core.API/Progranm.cs @@ -101,7 +101,7 @@ builder.Services.AddExceptionHandler(); builder.Services.AddHealthChecks(); builder.Services.AddSerilog(); //本地化 -builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resources"); +builder.Services.AddJsonLocalization(options => options.ResourcesPath = new[] { "Resources" }); // 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim() builder.Services.AddControllers(options => diff --git a/IRaCIS.Core.API/_ServiceExtensions/SwaggerSetup.cs b/IRaCIS.Core.API/_ServiceExtensions/SwaggerSetup.cs index ebba8c3ca..1ef0134b8 100644 --- a/IRaCIS.Core.API/_ServiceExtensions/SwaggerSetup.cs +++ b/IRaCIS.Core.API/_ServiceExtensions/SwaggerSetup.cs @@ -1,15 +1,7 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.Filters; -using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.SwaggerUI; -using System; using System.ComponentModel; -using System.IO; -using System.Linq; using System.Reflection; namespace IRaCIS.Core.API; @@ -52,18 +44,21 @@ public static class SwaggerSetup services.AddSwaggerGen(options => { - typeof(SwaggerVersion).GetFields(BindingFlags.Public | BindingFlags.Static).ToList() - .ForEach(field => - { - var description = field.GetCustomAttribute()?.Description ?? field.Name; - options.SwaggerDoc(field.Name, new Microsoft.OpenApi.Models.OpenApiInfo - { - Version = field.Name, - Description = $"{field.Name} API", - Title = description // 使用Description作为Title - }); - }); + // 使用反射获取字段并动态创建 Swagger 文档 + typeof(SwaggerVersion).GetFields(BindingFlags.Public | BindingFlags.Static) + .ToList() + .ForEach(field => + { + var description = field.GetCustomAttribute()?.Description ?? field.Name; + options.SwaggerDoc(field.Name, new OpenApiInfo + { + Version = field.Name, + Description = $"{field.Name} API", + Title = description // 使用 Description 作为 Title + }); + }); + // 接口排序 options.OrderActionsBy(o => o.GroupName); diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj index 932767881..33fb33999 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj @@ -1,9 +1,7 @@  - net8.0 default - enable enable True @@ -35,10 +33,10 @@ - - + + - + @@ -47,23 +45,23 @@ - + - - - - + + + + - + true - + diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml index 399663612..1c977b4e1 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml @@ -17295,17 +17295,17 @@ - ���� + 质疑 - һ���Ժ˲� + 一致性核查 - ���� + 复制 @@ -21859,5 +21859,49 @@ 入组流程-向CRO提交医生[Submit] + + + Generates a documentation comment ID for a type. + Example: T:Namespace.Outer+Inner`1 becomes T:Namespace.Outer.Inner`1 + + + + + Generates a documentation comment ID for a property. + Example: P:Namespace.ContainingType.PropertyName or for an indexer P:Namespace.ContainingType.Item(System.Int32) + + + + + Generates a documentation comment ID for a property given its container type and property name. + Example: P:Namespace.ContainingType.PropertyName + + + + + Generates a documentation comment ID for a method (or constructor). + For example: + M:Namespace.ContainingType.MethodName(ParamType1,ParamType2)~ReturnType + M:Namespace.ContainingType.#ctor(ParamType) + + + + + Generates a documentation ID string for a type. + This method handles nested types (replacing '+' with '.'), + generic types, arrays, pointers, by-ref types, and generic parameters. + The flag controls whether + constructed generic type arguments are emitted, while + controls whether the generic arity marker (e.g. "`1") is appended. + + + + + Normalizes a documentation comment ID to match the compiler-style format. + Strips the return type suffix for ordinary methods but retains it for conversion operators. + + The documentation comment ID to normalize. + The normalized documentation comment ID. + diff --git a/IRaCIS.Core.Application/Service/MinimalApiService/OAuthService.cs b/IRaCIS.Core.Application/Service/MinimalApiService/OAuthService.cs index 21700e1d7..9758df471 100644 --- a/IRaCIS.Core.Application/Service/MinimalApiService/OAuthService.cs +++ b/IRaCIS.Core.Application/Service/MinimalApiService/OAuthService.cs @@ -1,6 +1,4 @@ -using Azure.Core; -using IdentityModel; -using IdentityModel.Client; +using IdentityModel.Client; using IRaCIS.Core.Application.Service.OAuth; using MassTransit; using Microsoft.AspNetCore.Authorization; @@ -8,18 +6,11 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using NPOI.SS.Formula.Functions; -using Org.BouncyCastle.Utilities.Net; using RestSharp; -using System; -using System.Collections.Generic; -using System.Linq; using System.Net; -using System.Net.Http; using System.Security.Cryptography; using System.Text; using System.Text.Json; -using System.Threading.Tasks; namespace IRaCIS.Core.Application.Service { diff --git a/IRaCIS.Core.Application/TestService.cs b/IRaCIS.Core.Application/TestService.cs index 7825aed6a..fa05a896e 100644 --- a/IRaCIS.Core.Application/TestService.cs +++ b/IRaCIS.Core.Application/TestService.cs @@ -1,30 +1,17 @@ using Aliyun.OSS; -using DocumentFormat.OpenXml.Spreadsheet; using FellowOakDicom; using FellowOakDicom.Imaging; using IRaCIS.Application.Contracts; -using IRaCIS.Core.Application.BusinessFilter; using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Helper; -using IRaCIS.Core.Application.Helper.OtherTool; -using IRaCIS.Core.Application.Service.BusinessFilter; using IRaCIS.Core.Application.ViewModel; -using IRaCIS.Core.Domain; -using IRaCIS.Core.Domain.Models; -using IRaCIS.Core.Domain.Share; -using IRaCIS.Core.Infra.EFCore; using IRaCIS.Core.Infra.EFCore.Context; using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Infrastructure.Encryption; using IRaCIS.Core.Infrastructure.NewtonsoftJson; using MassTransit; -using MassTransit.Caching.Internals; -using MassTransit.Mediator; -using MathNet.Numerics; -using MaxMind.GeoIP2; using Medallion.Threading; using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -32,24 +19,14 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MiniExcelLibs; -using Minio.DataModel; -using NPOI.SS.Formula.Functions; using NPOI.XWPF.UserModel; -using SharpCompress.Common; 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; using System.Linq.Dynamic.Core; -using System.Reactive.Subjects; -using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; using System.Text; -using static IRaCIS.Core.Domain.Share.StaticData; diff --git a/IRaCIS.Core.Domain.Share/IRaCIS.Core.Domain.Share.csproj b/IRaCIS.Core.Domain.Share/IRaCIS.Core.Domain.Share.csproj index c901b7922..f0476682e 100644 --- a/IRaCIS.Core.Domain.Share/IRaCIS.Core.Domain.Share.csproj +++ b/IRaCIS.Core.Domain.Share/IRaCIS.Core.Domain.Share.csproj @@ -1,8 +1,5 @@  - - net8.0 - ..\bin diff --git a/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj b/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj index ec3436d81..b253bd06a 100644 --- a/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj +++ b/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj @@ -1,11 +1,4 @@  - - enable - - - net8.0 - - ..\bin @@ -16,8 +9,8 @@ - - - + + + diff --git a/IRaCIS.Core.Domain/Trial/Trial.cs b/IRaCIS.Core.Domain/Trial/Trial.cs index 6bc26f04d..41af70637 100644 --- a/IRaCIS.Core.Domain/Trial/Trial.cs +++ b/IRaCIS.Core.Domain/Trial/Trial.cs @@ -1,6 +1,5 @@ using IRaCIS.Core.Domain.Share; -using System.Linq; -using ZstdSharp.Unsafe; + namespace IRaCIS.Core.Domain.Models; diff --git a/IRaCIS.Core.Infra.EFCore/Context/DbContextExt.cs b/IRaCIS.Core.Infra.EFCore/Context/DbContextExt.cs deleted file mode 100644 index 81d671a24..000000000 --- a/IRaCIS.Core.Infra.EFCore/Context/DbContextExt.cs +++ /dev/null @@ -1,245 +0,0 @@ -using System.Collections; -using System.Reflection; - -namespace IRaCIS.Core.Infra.EFCore; - -public static class DbContextExt -{ - - /// - /// 获取变化的实体信息 - /// - /// - /// - /// - public static IEnumerable GetChanges(this DbContext db) - { - return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Modified && e.Entity is T).Select(e => - { - var originalObject = e.OriginalValues.ToObject(); - var currentObject = e.CurrentValues.ToObject(); - return new ChangeEntry - { - EntityState = e.State, - Entity = e.Entity, - EntityType = e.OriginalValues.EntityType.ClrType, - ChangeProperties = e.OriginalValues.Properties.Select(p => (Property: p, Value: p.PropertyInfo.GetValue(originalObject))).Zip(e.CurrentValues.Properties.Select(p => (Property: p, Value: p.PropertyInfo.GetValue(currentObject))), (t1, t2) => new ChangePropertyInfo() - { - PropertyInfo = t1.Property.PropertyInfo, - OriginalValue = t1.Value, - CurrentValue = t2.Value, - IsPrimaryKey = t1.Property.IsPrimaryKey(), - IsForeignKey = t1.Property.IsForeignKey() - }).Where(t => Comparer.Default.Compare(t.OriginalValue, t.CurrentValue) != 0).ToList() - }; - }); - } - - - - /// - /// 获取变化的实体信息 - /// - /// - /// - public static IEnumerable GetChanges(this DbContext db) - { - return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Modified).Select(e => - { - var originalObject = e.OriginalValues.ToObject(); - var currentObject = e.CurrentValues.ToObject(); - return new ChangeEntry() - { - EntityState = e.State, - Entity = e.Entity, - EntityType = e.OriginalValues.EntityType.ClrType, - ChangeProperties = e.OriginalValues.Properties.Select(p => (Property: p, Value: p.PropertyInfo.GetValue(originalObject))).Zip(e.CurrentValues.Properties.Select(p => (Property: p, Value: p.PropertyInfo.GetValue(currentObject))), (t1, t2) => new ChangePropertyInfo() - { - PropertyInfo = t1.Property.PropertyInfo, - OriginalValue = t1.Value, - CurrentValue = t2.Value, - IsPrimaryKey = t1.Property.IsPrimaryKey(), - IsForeignKey = t1.Property.IsForeignKey(), - }).Where(t => Comparer.Default.Compare(t.OriginalValue, t.CurrentValue) != 0).ToList() - }; - }); - } - - /// - /// 获取添加的实体信息 - /// - /// - /// - /// - public static IEnumerable GetAdded(this DbContext db) - { - return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Added && e.Entity is T).Select(e => - { - var currentObject = e.CurrentValues.ToObject(); - return new ChangeEntry - { - EntityState = e.State, - Entity = e.Entity, - EntityType = e.CurrentValues.EntityType.ClrType, - ChangeProperties = e.CurrentValues.Properties.Select(p => new ChangePropertyInfo() - { - PropertyInfo = p.PropertyInfo, - CurrentValue = p.PropertyInfo.GetValue(currentObject), - IsPrimaryKey = p.IsPrimaryKey(), - IsForeignKey = p.IsForeignKey(), - }).ToList() - }; - }); - } - - /// - /// 获取添加的实体信息 - /// - /// - /// - public static IEnumerable GetAdded(this DbContext db) - { - return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Added).Select(e => - { - var currentObject = e.CurrentValues.ToObject(); - return new ChangeEntry - { - EntityState = e.State, - Entity = e.Entity, - EntityType = e.CurrentValues.EntityType.ClrType, - ChangeProperties = e.CurrentValues.Properties.Select(p => new ChangePropertyInfo() - { - PropertyInfo = p.PropertyInfo, - CurrentValue = p.PropertyInfo.GetValue(currentObject), - IsPrimaryKey = p.IsPrimaryKey(), - IsForeignKey = p.IsForeignKey(), - }).ToList() - }; - }); - } - - /// - /// 获取移除的实体信息 - /// - /// - /// - /// - public static IEnumerable GetRemoved(this DbContext db) - { - return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Deleted && e.Entity is T).Select(e => - { - var originalObject = e.OriginalValues.ToObject(); - return new ChangeEntry - { - EntityState = e.State, - Entity = e.Entity, - EntityType = e.OriginalValues.EntityType.ClrType, - ChangeProperties = e.OriginalValues.Properties.Select(p => new ChangePropertyInfo() - { - PropertyInfo = p.PropertyInfo, - OriginalValue = p.PropertyInfo.GetValue(originalObject), - IsPrimaryKey = p.IsPrimaryKey(), - IsForeignKey = p.IsForeignKey(), - }).ToList() - }; - }); - } - - /// - /// 获取移除的实体信息 - /// - /// - /// - public static IEnumerable GetRemoved(this DbContext db) - { - return db.ChangeTracker.Entries().Where(e => e.State == EntityState.Deleted).Select(e => - { - var originalObject = e.OriginalValues.ToObject(); - return new ChangeEntry - { - EntityState = e.State, - Entity = e.Entity, - EntityType = e.OriginalValues.EntityType.ClrType, - ChangeProperties = e.OriginalValues.Properties.Select(p => new ChangePropertyInfo() - { - PropertyInfo = p.PropertyInfo, - OriginalValue = p.PropertyInfo.GetValue(originalObject), - IsPrimaryKey = p.IsPrimaryKey(), - IsForeignKey = p.IsForeignKey(), - }).ToList() - }; - }); - } - - /// - /// 获取所有的变更信息 - /// - /// - /// - /// - public static IEnumerable GetAllChanges(this DbContext db) - { - return GetChanges(db).Union(GetAdded(db)).Union(GetRemoved(db)); - } - - /// - /// 获取所有的变更信息 - /// - /// - /// - public static IEnumerable GetAllChanges(this DbContext db) - { - return GetChanges(db).Union(GetAdded(db)).Union(GetRemoved(db)); - } -} - -public class ChangePropertyInfo -{ - /// - /// 属性 - /// - public PropertyInfo PropertyInfo { get; set; } - - /// - /// 原始值 - /// - public object OriginalValue { get; set; } - - /// - /// 新值 - /// - public object CurrentValue { get; set; } - - /// - /// 是否是主键 - /// - public bool IsPrimaryKey { get; set; } - - /// - /// 是否是外键 - /// - public bool IsForeignKey { get; set; } -} - -public class ChangeEntry -{ - /// - /// 所属实体 - /// - public object Entity { get; set; } - - /// - /// 实体类型 - /// - public Type EntityType { get; set; } - - /// - /// 变更类型 - /// - public EntityState EntityState { get; set; } - - /// - /// 字段变更信息 - /// - public List ChangeProperties { get; set; } -} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj b/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj index e7cfdb367..c97493bd3 100644 --- a/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj +++ b/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj @@ -1,11 +1,4 @@ - - - enable - - - net8.0 - - + ..\bin @@ -21,22 +14,21 @@ - + - - - - - - - - - - + + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/IRaCIS.Core.Infra.EFCore/Repository/DynamicRelationalExtensions.cs b/IRaCIS.Core.Infra.EFCore/Repository/DynamicRelationalExtensions.cs index 11f5c0efc..9db536fe4 100644 --- a/IRaCIS.Core.Infra.EFCore/Repository/DynamicRelationalExtensions.cs +++ b/IRaCIS.Core.Infra.EFCore/Repository/DynamicRelationalExtensions.cs @@ -1,4 +1,5 @@ -using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Query; using System.Reflection; namespace IRaCIS.Core.Infra.EFCore @@ -6,37 +7,14 @@ namespace IRaCIS.Core.Infra.EFCore public static class DynamicRelationalExtensions { - //升级efcore9 RelationalQueryableExtensions-> EntityFrameworkQueryableExtensions - static MethodInfo UpdateMethodInfo = - typeof(RelationalQueryableExtensions).GetMethod(nameof(RelationalQueryableExtensions.ExecuteUpdate)); + ////升级efcore9 RelationalQueryableExtensions-> EntityFrameworkQueryableExtensions + //static MethodInfo UpdateMethodInfo = + // typeof(EntityFrameworkQueryableExtensions).GetMethod(nameof(EntityFrameworkQueryableExtensions.ExecuteUpdate)); static MethodInfo UpdateAsyncMethodInfo = - typeof(RelationalQueryableExtensions).GetMethod(nameof(RelationalQueryableExtensions.ExecuteUpdateAsync)); + typeof(EntityFrameworkQueryableExtensions).GetMethod(nameof(EntityFrameworkQueryableExtensions.ExecuteUpdateAsync)); - #region 避免使用 - public static int ExecuteUpdate(this IQueryable query, string fieldName, object? fieldValue) - { - var updateBody = BuildUpdateBody(query.ElementType, - new Dictionary { { fieldName, fieldValue } }); - - return (int)UpdateMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, new object?[] { query, updateBody }); - } - - public static int ExecuteUpdate(this IQueryable query, IReadOnlyDictionary fieldValues) - { - var updateBody = BuildUpdateBody(query.ElementType, fieldValues); - - return (int)UpdateMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, new object?[] { query, updateBody }); - } - public static Task ExecuteUpdateAsync(this IQueryable query, string fieldName, object? fieldValue, CancellationToken cancellationToken = default) - { - var updateBody = BuildUpdateBody(query.ElementType, - new Dictionary { { fieldName, fieldValue } }); - - return (Task)UpdateAsyncMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, new object?[] { query, updateBody, cancellationToken })!; - } - #endregion public static Dictionary ExtractFieldValues(this Expression> updateFactory) { @@ -64,50 +42,63 @@ namespace IRaCIS.Core.Infra.EFCore public static Task ExecuteUpdateAsync(this IQueryable query, IReadOnlyDictionary fieldValues, CancellationToken cancellationToken = default) { - var updateBody = BuildUpdateBody(query.ElementType, fieldValues); - return (Task)UpdateAsyncMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, new object?[] { query, updateBody, cancellationToken })!; + ParameterExpression propertyParam = Expression.Parameter(query.ElementType, "p"); + + Type SetPropertyBuilder = typeof(UpdateSettersBuilder<>).MakeGenericType(query.ElementType); + Action BuilderAction = r => { }; + foreach (KeyValuePair FieldValue in fieldValues) + { + MemberExpression propertyExp = Expression.PropertyOrField(propertyParam, FieldValue.Key); + MethodInfo? SetPropertyMethodInfo = (SetPropertyBuilder.GetMethods() + .FirstOrDefault(r => r.Name == nameof(UpdateSettersBuilder<>.SetProperty) && r.GetParameters().Any(p => p.ParameterType.BaseType == typeof(object)))? + .MakeGenericMethod(propertyExp.Type)) ?? throw new Exception("SetPropertyBuilder.SetProperty method is not found"); + BuilderAction += r => SetPropertyMethodInfo.Invoke(r, [Expression.Lambda(propertyExp, propertyParam), FieldValue.Value]); + } + return (Task)UpdateAsyncMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, [query, BuilderAction, cancellationToken])!; + } - static LambdaExpression BuildUpdateBody(Type entityType, IReadOnlyDictionary fieldValues) - { - var setParam = Expression.Parameter(typeof(SetPropertyCalls<>).MakeGenericType(entityType), "s"); - var objParam = Expression.Parameter(entityType, "e"); - Expression setBody = setParam; + //static LambdaExpression BuildUpdateBody(Type entityType, IReadOnlyDictionary fieldValues) + //{ + // var setParam = Expression.Parameter(typeof(SetPropertyCalls<>).MakeGenericType(entityType), "s"); + // var objParam = Expression.Parameter(entityType, "e"); - foreach (var pair in fieldValues) - { - var propExpression = Expression.PropertyOrField(objParam, pair.Key); - var valueExpression = ValueForType(propExpression.Type, pair.Value); + // Expression setBody = setParam; - // s.SetProperty(e => e.SomeField, value) - setBody = Expression.Call(setBody, nameof(SetPropertyCalls.SetProperty), - new[] { propExpression.Type }, Expression.Lambda(propExpression, objParam), valueExpression); + // foreach (var pair in fieldValues) + // { + // var propExpression = Expression.PropertyOrField(objParam, pair.Key); + // var valueExpression = ValueForType(propExpression.Type, pair.Value); - } + // // s.SetProperty(e => e.SomeField, value) + // setBody = Expression.Call(setBody, nameof(SetPropertyCalls.SetProperty), + // new[] { propExpression.Type }, Expression.Lambda(propExpression, objParam), valueExpression); - // s => s.SetProperty(e => e.SomeField, value) - var updateBody = Expression.Lambda(setBody, setParam); + // } - return updateBody; - } + // // s => s.SetProperty(e => e.SomeField, value) + // var updateBody = Expression.Lambda(setBody, setParam); - static Expression ValueForType(Type desiredType, object? value) - { - if (value == null) - { - return Expression.Default(desiredType); - } + // return updateBody; + //} - if (value.GetType() != desiredType) - { - return Expression.Convert(Expression.Constant(value), desiredType); - } + //static Expression ValueForType(Type desiredType, object? value) + //{ + // if (value == null) + // { + // return Expression.Default(desiredType); + // } - return Expression.Constant(value); - } + // if (value.GetType() != desiredType) + // { + // return Expression.Convert(Expression.Constant(value), desiredType); + // } + + // return Expression.Constant(value); + //} } } diff --git a/IRaCIS.Core.Infra.EFCore/Repository/ICommandRepository.cs b/IRaCIS.Core.Infra.EFCore/Repository/ICommandRepository.cs index e52fd8b90..6d5b05f72 100644 --- a/IRaCIS.Core.Infra.EFCore/Repository/ICommandRepository.cs +++ b/IRaCIS.Core.Infra.EFCore/Repository/ICommandRepository.cs @@ -60,7 +60,7 @@ namespace IRaCIS.Core.Infra.EFCore /// 批量更新,相当于原生sql, 没用EF跟踪方式(所有查询出来,再更新 浪费性能) Task BatchUpdateNoTrackingAsync(Expression> where, Expression> updateFactory, bool isAutoIncludeTimeAndUser = true); - Task ExecuteUpdateAsync(Expression> where, Expression, SetPropertyCalls>> setPropertyCalls); + Task ExecuteUpdateAsync(Expression> where, Action> setPropertyCalls); #endregion diff --git a/IRaCIS.Core.Infra.EFCore/Repository/IRaCISContextExtension.cs b/IRaCIS.Core.Infra.EFCore/Repository/IRaCISContextExtension.cs index ebd59fe2a..16cf6fe62 100644 --- a/IRaCIS.Core.Infra.EFCore/Repository/IRaCISContextExtension.cs +++ b/IRaCIS.Core.Infra.EFCore/Repository/IRaCISContextExtension.cs @@ -1,6 +1,7 @@ using IRaCIS.Core.Domain.Models; using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Infrastructure.Extention; +using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Query; using System.Reflection; @@ -220,6 +221,8 @@ namespace IRaCIS.Core.Infra.EFCore } return await _dbContext.Set().IgnoreQueryFilters().Where(where).ExecuteUpdateAsync(fieldValues).ConfigureAwait(false) > 0; + + } @@ -228,7 +231,8 @@ namespace IRaCIS.Core.Infra.EFCore } - public static async Task ExecuteUpdateAsync(this IRaCISDBContext _dbContext, Expression> where, Expression, SetPropertyCalls>> setPropertyCalls) where T : Entity + + public static async Task ExecuteUpdateAsync(this IRaCISDBContext _dbContext, Expression> where, Action> setPropertyCalls ) where T : Entity { return await _dbContext.Set().Where(where).ExecuteUpdateAsync(setPropertyCalls) > 0; diff --git a/IRaCIS.Core.Infra.EFCore/Repository/Repository.cs b/IRaCIS.Core.Infra.EFCore/Repository/Repository.cs index 3d35dbf60..2ed55ad81 100644 --- a/IRaCIS.Core.Infra.EFCore/Repository/Repository.cs +++ b/IRaCIS.Core.Infra.EFCore/Repository/Repository.cs @@ -306,7 +306,7 @@ namespace IRaCIS.Core.Infra.EFCore /// EF core 7+ 原生批量更新方法 - public async Task ExecuteUpdateAsync(Expression> where, Expression, SetPropertyCalls>> setPropertyCalls) + public async Task ExecuteUpdateAsync(Expression> where, Action> setPropertyCalls) { return await _dbContext.ExecuteUpdateAsync(where, setPropertyCalls); } diff --git a/IRaCIS.Core.Infrastructure/Extention/SevenZipCompressor.cs b/IRaCIS.Core.Infrastructure/Extention/SevenZipCompressor.cs deleted file mode 100644 index b703ae2a4..000000000 --- a/IRaCIS.Core.Infrastructure/Extention/SevenZipCompressor.cs +++ /dev/null @@ -1,205 +0,0 @@ -using SharpCompress.Archives; -using SharpCompress.Common; -using SharpCompress.Readers; -using SharpCompress.Writers; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using System.Web; - -namespace IRaCIS.Core.Infrastructure.Extention -{ - /// - /// 7z压缩 - /// - public static class SevenZipCompressor - { - /// - /// 将多个文件压缩到一个内存流中,可保存为zip文件,方便于web方式下载 - /// - /// 多个文件路径,文件或文件夹,或网络路径http/https - /// - /// 文件流 - public static MemoryStream ZipStream(List files, string rootdir = "") - { - using var archive = CreateZipArchive(files, rootdir); - var ms = new MemoryStream(); - archive.SaveTo(ms, new WriterOptions(CompressionType.Deflate) - { - LeaveStreamOpen = true, - ArchiveEncoding = new ArchiveEncoding() - { - Default = Encoding.UTF8 - } - }); - return ms; - } - - /// - /// 压缩多个文件 - /// - /// 多个文件路径,文件或文件夹 - /// 压缩到... - /// 压缩包内部根文件夹 - /// - public static void Zip(List files, string zipFile, string rootdir = "", ArchiveType archiveType = ArchiveType.SevenZip) - { - using var archive = CreateZipArchive(files, rootdir, archiveType); - archive.SaveTo(zipFile, new WriterOptions(CompressionType.Deflate) - { - LeaveStreamOpen = true, - ArchiveEncoding = new ArchiveEncoding() - { - Default = Encoding.UTF8 - } - }); - } - - /// - /// 解压文件,自动检测压缩包类型 - /// - /// rar文件 - /// 解压到... - /// 忽略空文件夹 - public static void Decompress(string compressedFile, string dir = "", bool ignoreEmptyDir = true) - { - if (string.IsNullOrEmpty(dir)) - { - dir = Path.GetDirectoryName(compressedFile); - } - - using Stream stream = File.OpenRead(compressedFile); - using var reader = ReaderFactory.Open(stream); - while (reader.MoveToNextEntry()) - { - if (ignoreEmptyDir) - { - reader.WriteEntryToDirectory(dir, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); - } - else - { - if (!reader.Entry.IsDirectory) - { - reader.WriteEntryToDirectory(dir, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); - } - } - } - } - - /// - /// 创建zip包 - /// - /// - /// - /// - /// - private static IWritableArchive CreateZipArchive(List files, string rootdir, ArchiveType archiveType = ArchiveType.SevenZip) - { - var archive = ArchiveFactory.Create(archiveType); - var dic = GetFileEntryMaps(files); - var remoteUrls = files.Distinct().Where(s => s.StartsWith("http")).Select(s => - { - try - { - return new Uri(s); - } - catch (UriFormatException) - { - return null; - } - }).Where(u => u != null).ToList(); - foreach (var pair in dic) - { - archive.AddEntry(Path.Combine(rootdir, pair.Value), pair.Key); - } - - if (!remoteUrls.Any()) - { - return archive; - } - - var streams = new ConcurrentDictionary(); - using var httpClient = new HttpClient(); - Parallel.ForEach(remoteUrls, url => - { - httpClient.GetAsync(url).ContinueWith(async t => - { - if (t.IsCompleted) - { - var res = await t; - if (res.IsSuccessStatusCode) - { - Stream stream = await res.Content.ReadAsStreamAsync(); - streams[Path.Combine(rootdir, Path.GetFileName(HttpUtility.UrlDecode(url.AbsolutePath)))] = stream; - } - } - }).Wait(); - }); - foreach (var kv in streams) - { - archive.AddEntry(kv.Key, kv.Value, true); - } - - return archive; - } - - /// - /// 获取文件路径和zip-entry的映射 - /// - /// - /// - private static Dictionary GetFileEntryMaps(List files) - { - var fileList = new List(); - void GetFilesRecurs(string path) - { - //遍历目标文件夹的所有文件 - fileList.AddRange(Directory.GetFiles(path)); - - //遍历目标文件夹的所有文件夹 - foreach (string directory in Directory.GetDirectories(path)) - { - GetFilesRecurs(directory); - } - } - - files.Where(s => !s.StartsWith("http")).ForEach(s => - { - if (Directory.Exists(s)) - { - GetFilesRecurs(s); - } - else - { - fileList.Add(s); - } - }); - if (!fileList.Any()) - { - return new Dictionary(); - } - - var dirname = new string(fileList.First().Substring(0, fileList.Min(s => s.Length)).TakeWhile((c, i) => fileList.All(s => s[i] == c)).ToArray()); - if (!Directory.Exists(dirname)) - { - dirname = Directory.GetParent(dirname).FullName; - } - - var dic = fileList.ToDictionary(s => s, s => s.Substring(dirname.Length)); - return dic; - } - } -} diff --git a/IRaCIS.Core.Infrastructure/IRaCIS.Core.Infrastructure.csproj b/IRaCIS.Core.Infrastructure/IRaCIS.Core.Infrastructure.csproj index e0ee437d6..87841c958 100644 --- a/IRaCIS.Core.Infrastructure/IRaCIS.Core.Infrastructure.csproj +++ b/IRaCIS.Core.Infrastructure/IRaCIS.Core.Infrastructure.csproj @@ -1,25 +1,21 @@  - - net8.0 - - ..\bin - - - - - - - + + + + + + + - - - + + + diff --git a/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj b/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj index bb69e4176..47fdcb288 100644 --- a/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj +++ b/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj @@ -1,9 +1,6 @@  + - enable - - - net8.0 false @@ -49,11 +46,11 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive