diff --git a/IRaCIS.Core.API/IRaCIS.Core.API.csproj b/IRaCIS.Core.API/IRaCIS.Core.API.csproj index 090939cbe..f274cf612 100644 --- a/IRaCIS.Core.API/IRaCIS.Core.API.csproj +++ b/IRaCIS.Core.API/IRaCIS.Core.API.csproj @@ -89,63 +89,6 @@ - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/AdminAddUser.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/AdminAddUser.html deleted file mode 100644 index 9a6dc6f9d..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/AdminAddUser.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - Title - - -
-
-
- 尊敬的 {0} ,您好: -
-
- {company abbreviation}为您添加了账户,账户信息如下: -
- -
-
- 用户名: {1} -
-
- 角色: {2} -
-
- 首次登陆前,请通过该链接修改您的账户信息: - - 初始化账号信息 - -
-
- - -
-
祝您顺利!
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/AdminAddUser_US.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/AdminAddUser_US.html deleted file mode 100644 index 04453f355..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/AdminAddUser_US.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - Title - - -
-
-
- Dear {0} , -
-
- {company abbreviation} has created an account for you. The account information is as follows: -
- -
-
- User ID: {1} -
-
- Role: {2} -
-
- Before logging in for the first time, please modify the account information through this link: - - Initialize account information - -
-
- - -
-
Best regards,
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/AdminResetUser.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/AdminResetUser.html deleted file mode 100644 index 3354b1a34..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/AdminResetUser.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - Title - - -
-
-
- 尊敬的 {0} ,您好: -
-
- {company abbreviation}将您的账户密码已重置,账户信息如下: -
- -
-
- 用户名: {1} -
-
- 角色: {2} -
-
- 密码: {3} -
-
- - -
-
祝您顺利!
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/AdminResetUser_US.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/AdminResetUser_US.html deleted file mode 100644 index 7d515cabb..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/AdminResetUser_US.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - Title - - -
-
-
- Dear {0} , -
-
- {company abbreviation} has reset your account password, and the account information is as follows: -
- -
-
- User ID: {1} -
-
- Role: {2} -
-
- Password: {3} -
-
- - -
-
Best regards,
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/SubjectEnrollConfirmOrPDProgress.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/SubjectEnrollConfirmOrPDProgress.html deleted file mode 100644 index 1becb5c55..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/SubjectEnrollConfirmOrPDProgress.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - Title - - -
-
-
- 您好: -
-
- 感谢您使用展影云平台。 -
-
- {0}。 -
- -
-
祝您顺利!
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/SubjectEnrollConfirmOrPDProgress_US.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/SubjectEnrollConfirmOrPDProgress_US.html deleted file mode 100644 index e5d5f6b58..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/SubjectEnrollConfirmOrPDProgress_US.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - Title - - -
-
-
- Dear: -
-
- Thank you for using {company abbreviation} Cloud System. -
-
- {0}。 -
- -
-
Best regards,
-
{company}
-
-
-
- - \ No newline at end of file diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorExistJoin.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorExistJoin.html deleted file mode 100644 index c56b85bc7..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorExistJoin.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - Title - - -
-
-
- 尊敬的 {0} ,您好: -
-
- {company abbreviation}作为 [{1} (试验方案号:{2 })] 项目的供应商,诚邀您参加该项目阅片相关工作。 -
-
- 该项目采用电子化工作流,系统及您的账号信息如下: -
- -
-
- 项目编号: {3} -
-
- 试验方案号: {2} -
-
- 试验名称: {1} -
-
- 用户名: {4} -
-
- 角色: {5} -
-
- 系统登录地址: - - 点击跳转 - -
-
- -
-
祝您顺利!
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorExistJoin_US.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorExistJoin_US.html deleted file mode 100644 index 1558db0a4..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorExistJoin_US.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - Title - - -
-
-
- Dear {0}, -
-
- {company abbreviation} invites you to participate in the IRC work of a trial ({1} , {2}). -
-
- Your account information is as follows: -
- -
-
- Trial ID: {3} -
-
- Protocol ID: {2} -
-
- Study Name: {1} -
-
- User ID: {4} -
-
- Role: {5} -
-
- Login URL: - - Click to login - -
-
- - -
-
Best regards,
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorFirstJoin.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorFirstJoin.html deleted file mode 100644 index 1ac10ce08..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorFirstJoin.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - Title - - -
-
-
- 尊敬的 {0} ,您好: -
-
- {company abbreviation}作为 [{1} (试验方案号:{2 })] 项目的IRC供应商,诚邀您参加该项目IRC阅片相关工作,欢迎您提供指导和建议,非常感谢! -
-
- 该项目采用电子化工作流,系统及您的账号信息如下: -
- -
-
- 项目编号: {3} -
-
- 试验方案号: {2} -
-
- 试验名称: {1} -
-
- 用户名: {4} -
-
- 角色: {5} -
-
- 首次登陆前,请通过该链接修改您的账户信息: - - 初始化账号信息 - -
-
- - -
-
祝您顺利!
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorFirstJoin_US.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorFirstJoin_US.html deleted file mode 100644 index 56f832794..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorFirstJoin_US.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - Title - - -
-
-
- Dear {0}, -
-
- {company abbreviation} invites you to participate in the IRC work of a trial ({1}, {2}). -
-
- Your account information is as follows: -
- -
-
- Trial ID: {3} -
-
- Protocol ID: {2} -
-
- Study Name: {1} -
-
- User ID: {4} -
-
- Role: {5} -
-
- Before logging in for the first time, please modify the account information through this link: - - Initialize account information - -
-
- - -
-
Best regards,
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialSiteSurveyReject.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialSiteSurveyReject.html deleted file mode 100644 index 70cf1bdec..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialSiteSurveyReject.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - Title - - -
-
-
- 尊敬的 {0} ,您好: -
-
- 您填写的中心调研表被驳回,详细信息如下: -
- -
-
- 项目编号: {1} -
-
- 试验方案号: {2} -
-
- 试验名称: {3} -
-
- 中心编号: {4} -
-
- 中心名称: {5} -
-
- 驳回原因: {6} -
- -
- - 登陆并查看 - - -
-
祝您顺利!
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialSiteSurveyReject_US.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialSiteSurveyReject_US.html deleted file mode 100644 index 4a7064460..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialSiteSurveyReject_US.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - Title - - -
-
-
- Dear {0} , -
-
- The site survey form you filled in has been rejected. The details are as follows: -
- -
-
- Trial ID: {1} -
-
- Protocol ID: {2} -
-
- Study Name: {3} -
-
- Site ID: {4} -
-
- Site name: {5} -
-
- Reason for rejection: {6} -
- -
- - Login and view - - -
-
Best regards,
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialUserExistJoin.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialUserExistJoin.html deleted file mode 100644 index f3d816b3c..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialUserExistJoin.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - Title - - -
-
-
- 尊敬的 {0} ,您好: -
-
- {company abbreviation}作为 [{1} (试验方案号:{2 })] 项目的供应商,诚邀您参加该项目相关工作,欢迎您提供指导和建议,非常感谢! -
-
- 该项目采用电子化工作流,系统及您的账号信息如下: -
- -
-
- 项目编号: {3} -
-
- 试验方案号: {2} -
-
- 试验名称: {1} -
-
- 用户名: {4} -
-
- 角色: {5} -
-
- 系统登录地址: - - 点击跳转 - -
-
- - -
-
祝您顺利!
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialUserExistJoin_US.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialUserExistJoin_US.html deleted file mode 100644 index f965bf8b5..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialUserExistJoin_US.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - Title - - -
-
-
- Dear {0}, -
-
- {company abbreviation} invites you to participate in the IRC work of a trial ({1}, {2}). -
-
- Your account information is as follows: -
- -
-
- Trial ID: {3} -
-
- Protocol ID: {2} -
-
- Study Name: {1} -
-
- User ID: {4} -
-
- Role: {5} -
-
- Login URL: - - Click to login - -
-
- - -
-
Best regards,
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialUserFirstJoin.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialUserFirstJoin.html deleted file mode 100644 index 3fa857aa3..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialUserFirstJoin.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - Title - - -
-
-
- 尊敬的 {0} ,您好: -
-
- {company abbreviation}作为 [{1} (试验方案号:{2 })] 项目的IRC供应商,诚邀您参加该项目IRC相关工作,欢迎您提供指导和建议,非常感谢! -
-
- 该项目采用电子化工作流,系统及您的账号信息如下: -
- -
-
- 项目编号: {3} -
-
- 试验方案号: {2} -
-
- 试验名称: {1} -
-
- 用户名: {4} -
-
- 角色: {5} -
-
- 首次登陆前,请通过该链接修改您的账户信息: - - 初始化账号信息 - -
-
- - -
-
祝您顺利!
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialUserFirstJoin_US.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialUserFirstJoin_US.html deleted file mode 100644 index 8a047db59..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialUserFirstJoin_US.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - Title - - -
-
-
- Dear {0}, -
-
- {company abbreviation} invites you to participate in the IRC work of a trial ({1}, {2}). -
-
- Your account information is as follows: -
- -
-
- Trial ID: {3} -
-
- Protocol ID: {2} -
-
- Study Name: {1} -
-
- User ID: {4} -
-
- Role: {5} -
-
- Before logging in for the first time, please modify the account information through this link: - - Initialize the account information - -
-
- - -
-
Best regards,
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/UserOptCommon.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/UserOptCommon.html deleted file mode 100644 index db42758d2..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/UserOptCommon.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Title - - -
-
-
- {0}您好, -
-
- 感谢您使用展影云平台。 -
-
- {1},验证码是: {2}。 -
-
- 请在3分钟内输入该验证码,进行后续操作 -
-
-
祝您顺利!
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/UserOptCommon_US.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/UserOptCommon_US.html deleted file mode 100644 index 2d4abdab8..000000000 --- a/IRaCIS.Core.API/wwwroot/EmailTemplate/UserOptCommon_US.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - Title - - -
-
-
- Dear {0}, -
-
- {1} -
-
- The verification code is {2}. -
-
- This code will expire in 3 minutes. -
- -
-
Best regards,
-
{company}
-
-
-
- - diff --git a/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj b/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj index 15c6078d5..499dd8565 100644 --- a/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj +++ b/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj @@ -1,5 +1,8 @@  - + + enable + + net8.0 diff --git a/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs b/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs index 933e3990a..d6673ef2e 100644 --- a/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs +++ b/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs @@ -65,7 +65,24 @@ namespace IRaCIS.Core.Infra.EFCore protected override void OnModelCreating(ModelBuilder modelBuilder) { + #region pgsql codefirst 配置 暂时屏蔽 + //if (base.Database.IsNpgsql()) + //{ + // modelBuilder.HasPostgresExtension("uuid-ossp"); + // //保证pgsql 生成的时间默认为timestamp 而不是 timestamp with time zone + // foreach (var entityType in modelBuilder.Model.GetEntityTypes()) + // { + // foreach (var property in entityType.GetProperties()) + // { + // if (property.ClrType == typeof(DateTime) || property.ClrType == typeof(DateTime?)) + // { + // property.SetColumnType("timestamp without time zone"); + // } + // } + // } + //} + #endregion //遍历实体模型手动配置 var typesToRegister = Assembly.GetExecutingAssembly().GetTypes().Where(q => q.GetInterface(typeof(IEntityTypeConfiguration<>).FullName) != null); diff --git a/IRaCIS.Core.Test/CodeTemplates/EFCore/DbContext.t4 b/IRaCIS.Core.Test/CodeTemplates/EFCore/DbContext.t4 new file mode 100644 index 000000000..1351902b0 --- /dev/null +++ b/IRaCIS.Core.Test/CodeTemplates/EFCore/DbContext.t4 @@ -0,0 +1,355 @@ +<#@ template hostSpecific="true" #> +<#@ assembly name="Microsoft.EntityFrameworkCore" #> +<#@ assembly name="Microsoft.EntityFrameworkCore.Design" #> +<#@ assembly name="Microsoft.EntityFrameworkCore.Relational" #> +<#@ assembly name="Microsoft.Extensions.DependencyInjection.Abstractions" #> +<#@ parameter name="Model" type="Microsoft.EntityFrameworkCore.Metadata.IModel" #> +<#@ parameter name="Options" type="Microsoft.EntityFrameworkCore.Scaffolding.ModelCodeGenerationOptions" #> +<#@ parameter name="NamespaceHint" type="System.String" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="Microsoft.EntityFrameworkCore" #> +<#@ import namespace="Microsoft.EntityFrameworkCore.Design" #> +<#@ import namespace="Microsoft.EntityFrameworkCore.Infrastructure" #> +<#@ import namespace="Microsoft.EntityFrameworkCore.Scaffolding" #> +<#@ import namespace="Microsoft.Extensions.DependencyInjection" #> +<# + if (!ProductInfo.GetVersion().StartsWith("8.0")) + { + Warning("Your templates were created using an older version of Entity Framework. Additional features and bug fixes may be available. See https://aka.ms/efcore-docs-updating-templates for more information."); + } + + var services = (IServiceProvider)Host; + var providerCode = services.GetRequiredService(); + var annotationCodeGenerator = services.GetRequiredService(); + var code = services.GetRequiredService(); + + var usings = new List + { + "System", + "System.Collections.Generic", + "Microsoft.EntityFrameworkCore" + }; + + if (NamespaceHint != Options.ModelNamespace + && !string.IsNullOrEmpty(Options.ModelNamespace)) + { + usings.Add(Options.ModelNamespace); + } + + if (!string.IsNullOrEmpty(NamespaceHint)) + { +#> +namespace <#= NamespaceHint #>; + +<# + } +#> +public partial class <#= Options.ContextName #> : DbContext +{ +<# + if (!Options.SuppressOnConfiguring) + { +#> + public <#= Options.ContextName #>() + { + } + +<# + } +#> + public <#= Options.ContextName #>(DbContextOptions<<#= Options.ContextName #>> options) + : base(options) + { + } + +<# + foreach (var entityType in Model.GetEntityTypes().Where(e => !e.IsSimpleManyToManyJoinEntityType())) + { +#> + public virtual DbSet<<#= entityType.Name #>> <#= entityType.GetDbSetName() #> { get; set; } + +<# + } + + if (!Options.SuppressOnConfiguring) + { +#> + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) +<# + if (!Options.SuppressConnectionStringWarning) + { +#> +#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263. +<# + } + + var useProviderCall = providerCode.GenerateUseProvider(Options.ConnectionString); + usings.AddRange(useProviderCall.GetRequiredUsings()); +#> + => optionsBuilder<#= code.Fragment(useProviderCall, indent: 3) #>; + +<# + } + +#> + protected override void OnModelCreating(ModelBuilder modelBuilder) + { +<# + var anyConfiguration = false; + + var modelFluentApiCalls = Model.GetFluentApiCalls(annotationCodeGenerator); + if (modelFluentApiCalls != null) + { + usings.AddRange(modelFluentApiCalls.GetRequiredUsings()); +#> + modelBuilder<#= code.Fragment(modelFluentApiCalls, indent: 3) #>; +<# + anyConfiguration = true; + } + + StringBuilder mainEnvironment; + foreach (var entityType in Model.GetEntityTypes().Where(e => !e.IsSimpleManyToManyJoinEntityType())) + { + // Save all previously generated code, and start generating into a new temporary environment + mainEnvironment = GenerationEnvironment; + GenerationEnvironment = new StringBuilder(); + + if (anyConfiguration) + { + WriteLine(""); + } + + var anyEntityTypeConfiguration = false; +#> + modelBuilder.Entity<<#= entityType.Name #>>(entity => + { +<# + var key = entityType.FindPrimaryKey(); + if (key != null) + { + var keyFluentApiCalls = key.GetFluentApiCalls(annotationCodeGenerator); + if (keyFluentApiCalls != null + || (!key.IsHandledByConvention() && !Options.UseDataAnnotations)) + { + if (keyFluentApiCalls != null) + { + usings.AddRange(keyFluentApiCalls.GetRequiredUsings()); + } +#> + entity.HasKey(<#= code.Lambda(key.Properties, "e") #>)<#= code.Fragment(keyFluentApiCalls, indent: 4) #>; +<# + anyEntityTypeConfiguration = true; + } + } + + var entityTypeFluentApiCalls = entityType.GetFluentApiCalls(annotationCodeGenerator) + ?.FilterChain(c => !(Options.UseDataAnnotations && c.IsHandledByDataAnnotations)); + if (entityTypeFluentApiCalls != null) + { + usings.AddRange(entityTypeFluentApiCalls.GetRequiredUsings()); + + if (anyEntityTypeConfiguration) + { + WriteLine(""); + } +#> + entity<#= code.Fragment(entityTypeFluentApiCalls, indent: 4) #>; +<# + anyEntityTypeConfiguration = true; + } + + foreach (var index in entityType.GetIndexes() + .Where(i => !(Options.UseDataAnnotations && i.IsHandledByDataAnnotations(annotationCodeGenerator)))) + { + if (anyEntityTypeConfiguration) + { + WriteLine(""); + } + + var indexFluentApiCalls = index.GetFluentApiCalls(annotationCodeGenerator); + if (indexFluentApiCalls != null) + { + usings.AddRange(indexFluentApiCalls.GetRequiredUsings()); + } +#> + entity.HasIndex(<#= code.Lambda(index.Properties, "e") #>, <#= code.Literal(index.GetDatabaseName()) #>)<#= code.Fragment(indexFluentApiCalls, indent: 4) #>; +<# + anyEntityTypeConfiguration = true; + } + + var firstProperty = true; + foreach (var property in entityType.GetProperties()) + { + var propertyFluentApiCalls = property.GetFluentApiCalls(annotationCodeGenerator) + ?.FilterChain(c => !(Options.UseDataAnnotations && c.IsHandledByDataAnnotations) + && !(c.Method == "IsRequired" && Options.UseNullableReferenceTypes && !property.ClrType.IsValueType)); + if (propertyFluentApiCalls == null) + { + continue; + } + + usings.AddRange(propertyFluentApiCalls.GetRequiredUsings()); + + if (anyEntityTypeConfiguration && firstProperty) + { + WriteLine(""); + } +#> + entity.Property(e => e.<#= property.Name #>)<#= code.Fragment(propertyFluentApiCalls, indent: 4) #>; +<# + anyEntityTypeConfiguration = true; + firstProperty = false; + } + + foreach (var foreignKey in entityType.GetForeignKeys()) + { + var foreignKeyFluentApiCalls = foreignKey.GetFluentApiCalls(annotationCodeGenerator) + ?.FilterChain(c => !(Options.UseDataAnnotations && c.IsHandledByDataAnnotations)); + if (foreignKeyFluentApiCalls == null) + { + continue; + } + + usings.AddRange(foreignKeyFluentApiCalls.GetRequiredUsings()); + + if (anyEntityTypeConfiguration) + { + WriteLine(""); + } +#> + entity.HasOne(d => d.<#= foreignKey.DependentToPrincipal.Name #>).<#= foreignKey.IsUnique ? "WithOne" : "WithMany" #>(<#= foreignKey.PrincipalToDependent != null ? $"p => p.{foreignKey.PrincipalToDependent.Name}" : "" #>)<#= code.Fragment(foreignKeyFluentApiCalls, indent: 4) #>; +<# + anyEntityTypeConfiguration = true; + } + + foreach (var skipNavigation in entityType.GetSkipNavigations().Where(n => n.IsLeftNavigation())) + { + if (anyEntityTypeConfiguration) + { + WriteLine(""); + } + + var left = skipNavigation.ForeignKey; + var leftFluentApiCalls = left.GetFluentApiCalls(annotationCodeGenerator, useStrings: true); + var right = skipNavigation.Inverse.ForeignKey; + var rightFluentApiCalls = right.GetFluentApiCalls(annotationCodeGenerator, useStrings: true); + var joinEntityType = skipNavigation.JoinEntityType; + + if (leftFluentApiCalls != null) + { + usings.AddRange(leftFluentApiCalls.GetRequiredUsings()); + } + + if (rightFluentApiCalls != null) + { + usings.AddRange(rightFluentApiCalls.GetRequiredUsings()); + } +#> + entity.HasMany(d => d.<#= skipNavigation.Name #>).WithMany(p => p.<#= skipNavigation.Inverse.Name #>) + .UsingEntity>( + <#= code.Literal(joinEntityType.Name) #>, + r => r.HasOne<<#= right.PrincipalEntityType.Name #>>().WithMany()<#= code.Fragment(rightFluentApiCalls, indent: 6) #>, + l => l.HasOne<<#= left.PrincipalEntityType.Name #>>().WithMany()<#= code.Fragment(leftFluentApiCalls, indent: 6) #>, + j => + { +<# + var joinKey = joinEntityType.FindPrimaryKey(); + var joinKeyFluentApiCalls = joinKey.GetFluentApiCalls(annotationCodeGenerator); + + if (joinKeyFluentApiCalls != null) + { + usings.AddRange(joinKeyFluentApiCalls.GetRequiredUsings()); + } +#> + j.HasKey(<#= code.Arguments(joinKey.Properties.Select(e => e.Name)) #>)<#= code.Fragment(joinKeyFluentApiCalls, indent: 7) #>; +<# + var joinEntityTypeFluentApiCalls = joinEntityType.GetFluentApiCalls(annotationCodeGenerator); + if (joinEntityTypeFluentApiCalls != null) + { + usings.AddRange(joinEntityTypeFluentApiCalls.GetRequiredUsings()); +#> + j<#= code.Fragment(joinEntityTypeFluentApiCalls, indent: 7) #>; +<# + } + + foreach (var index in joinEntityType.GetIndexes()) + { + var indexFluentApiCalls = index.GetFluentApiCalls(annotationCodeGenerator); + if (indexFluentApiCalls != null) + { + usings.AddRange(indexFluentApiCalls.GetRequiredUsings()); + } +#> + j.HasIndex(<#= code.Literal(index.Properties.Select(e => e.Name).ToArray()) #>, <#= code.Literal(index.GetDatabaseName()) #>)<#= code.Fragment(indexFluentApiCalls, indent: 7) #>; +<# + } + + foreach (var property in joinEntityType.GetProperties()) + { + var propertyFluentApiCalls = property.GetFluentApiCalls(annotationCodeGenerator); + if (propertyFluentApiCalls == null) + { + continue; + } + + usings.AddRange(propertyFluentApiCalls.GetRequiredUsings()); +#> + j.IndexerProperty<<#= code.Reference(property.ClrType) #>>(<#= code.Literal(property.Name) #>)<#= code.Fragment(propertyFluentApiCalls, indent: 7) #>; +<# + } +#> + }); +<# + anyEntityTypeConfiguration = true; + } +#> + }); +<# + // If any signicant code was generated, append it to the main environment + if (anyEntityTypeConfiguration) + { + mainEnvironment.Append(GenerationEnvironment); + anyConfiguration = true; + } + + // Resume generating code into the main environment + GenerationEnvironment = mainEnvironment; + } + + foreach (var sequence in Model.GetSequences()) + { + var needsType = sequence.Type != typeof(long); + var needsSchema = !string.IsNullOrEmpty(sequence.Schema) && sequence.Schema != sequence.Model.GetDefaultSchema(); + var sequenceFluentApiCalls = sequence.GetFluentApiCalls(annotationCodeGenerator); +#> + modelBuilder.HasSequence<#= needsType ? $"<{code.Reference(sequence.Type)}>" : "" #>(<#= code.Literal(sequence.Name) #><#= needsSchema ? $", {code.Literal(sequence.Schema)}" : "" #>)<#= code.Fragment(sequenceFluentApiCalls, indent: 3) #>; +<# + } + + if (anyConfiguration) + { + WriteLine(""); + } +#> + OnModelCreatingPartial(modelBuilder); + } + + partial void OnModelCreatingPartial(ModelBuilder modelBuilder); +} +<# + mainEnvironment = GenerationEnvironment; + GenerationEnvironment = new StringBuilder(); + + foreach (var ns in usings.Distinct().OrderBy(x => x, new NamespaceComparer())) + { +#> +using <#= ns #>; +<# + } + + WriteLine(""); + + GenerationEnvironment.Append(mainEnvironment); +#> diff --git a/IRaCIS.Core.Test/CodeTemplates/EFCore/EntityType.t4 b/IRaCIS.Core.Test/CodeTemplates/EFCore/EntityType.t4 new file mode 100644 index 000000000..260898361 --- /dev/null +++ b/IRaCIS.Core.Test/CodeTemplates/EFCore/EntityType.t4 @@ -0,0 +1,169 @@ +<#@ template hostSpecific="true" #> +<#@ assembly name="Microsoft.EntityFrameworkCore" #> +<#@ assembly name="Microsoft.EntityFrameworkCore.Design" #> +<#@ assembly name="Microsoft.EntityFrameworkCore.Relational" #> +<#@ assembly name="Microsoft.Extensions.DependencyInjection.Abstractions" #> +<#@ parameter name="EntityType" type="Microsoft.EntityFrameworkCore.Metadata.IEntityType" #> +<#@ parameter name="Options" type="Microsoft.EntityFrameworkCore.Scaffolding.ModelCodeGenerationOptions" #> +<#@ parameter name="NamespaceHint" type="System.String" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.ComponentModel.DataAnnotations" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="Microsoft.EntityFrameworkCore" #> +<#@ import namespace="Microsoft.EntityFrameworkCore.Design" #> +<#@ import namespace="Microsoft.Extensions.DependencyInjection" #> +<# + if (EntityType.IsSimpleManyToManyJoinEntityType()) + { + // Don't scaffold these + return ""; + } + + var services = (IServiceProvider)Host; + var annotationCodeGenerator = services.GetRequiredService(); + var code = services.GetRequiredService(); + + var usings = new List + { + "System", + "System.Collections.Generic" + }; + + if (Options.UseDataAnnotations) + { + usings.Add("System.ComponentModel.DataAnnotations"); + usings.Add("System.ComponentModel.DataAnnotations.Schema"); + usings.Add("Microsoft.EntityFrameworkCore"); + } + + if (!string.IsNullOrEmpty(NamespaceHint)) + { +#> +namespace <#= NamespaceHint #>; + +<# + } + + if (!string.IsNullOrEmpty(EntityType.GetComment())) + { +#> +[comment("<#= code.XmlComment(EntityType.GetComment()) #>")] +<# + } + + if (Options.UseDataAnnotations) + { + foreach (var dataAnnotation in EntityType.GetDataAnnotations(annotationCodeGenerator)) + { +#> +<#= code.Fragment(dataAnnotation) #> +<# + } + } +#> +public partial class <#= EntityType.Name #> +{ +<# + var firstProperty = true; + foreach (var property in EntityType.GetProperties().OrderBy(p => p.GetColumnOrder() ?? -1)) + { + if (!firstProperty) + { + WriteLine(""); + } + + if (!string.IsNullOrEmpty(property.GetComment())) + { +#> + [Comment(" <#= code.XmlComment(property.GetComment()) #>")] +<# + } + + if (Options.UseDataAnnotations) + { + var dataAnnotations = property.GetDataAnnotations(annotationCodeGenerator) + .Where(a => !(a.Type == typeof(RequiredAttribute) && Options.UseNullableReferenceTypes && !property.ClrType.IsValueType)); + foreach (var dataAnnotation in dataAnnotations) + { +#> + <#= code.Fragment(dataAnnotation) #> +<# + } + } + + usings.AddRange(code.GetRequiredUsings(property.ClrType)); + + var needsNullable = Options.UseNullableReferenceTypes && property.IsNullable && !property.ClrType.IsValueType; + var needsInitializer = Options.UseNullableReferenceTypes && !property.IsNullable && !property.ClrType.IsValueType; +#> + public <#= code.Reference(property.ClrType) #><#= needsNullable ? "?" : "" #> <#= property.Name #> { get; set; }<#= needsInitializer ? " = null!;" : "" #> +<# + firstProperty = false; + } + + foreach (var navigation in EntityType.GetNavigations()) + { + WriteLine(""); + + if (Options.UseDataAnnotations) + { + foreach (var dataAnnotation in navigation.GetDataAnnotations(annotationCodeGenerator)) + { +#> + <#= code.Fragment(dataAnnotation) #> +<# + } + } + + var targetType = navigation.TargetEntityType.Name; + if (navigation.IsCollection) + { +#> + public virtual ICollection<<#= targetType #>> <#= navigation.Name #> { get; set; } = new List<<#= targetType #>>(); +<# + } + else + { + var needsNullable = Options.UseNullableReferenceTypes && !(navigation.ForeignKey.IsRequired && navigation.IsOnDependent); + var needsInitializer = Options.UseNullableReferenceTypes && navigation.ForeignKey.IsRequired && navigation.IsOnDependent; +#> + public virtual <#= targetType #><#= needsNullable ? "?" : "" #> <#= navigation.Name #> { get; set; }<#= needsInitializer ? " = null!;" : "" #> +<# + } + } + + foreach (var skipNavigation in EntityType.GetSkipNavigations()) + { + WriteLine(""); + + if (Options.UseDataAnnotations) + { + foreach (var dataAnnotation in skipNavigation.GetDataAnnotations(annotationCodeGenerator)) + { +#> + <#= code.Fragment(dataAnnotation) #> +<# + } + } +#> + public virtual ICollection<<#= skipNavigation.TargetEntityType.Name #>> <#= skipNavigation.Name #> { get; set; } = new List<<#= skipNavigation.TargetEntityType.Name #>>(); +<# + } +#> +} +<# + var previousOutput = GenerationEnvironment; + GenerationEnvironment = new StringBuilder(); + + foreach (var ns in usings.Distinct().OrderBy(x => x, new NamespaceComparer())) + { +#> +using <#= ns #>; +<# + } + + WriteLine(""); + + GenerationEnvironment.Append(previousOutput); +#> diff --git a/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj b/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj index 39a20fd0c..823477b44 100644 --- a/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj +++ b/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj @@ -1,107 +1,111 @@  + + enable + + + + net8.0 - - net8.0 + false - false + default - default + Exe + - Exe - + + bin + - - bin - - - - - - - + + + + + - - - Always - - - Always - - - Always - - - IRaCIS .Core.ServiceAsync.cs - TextTemplatingFileGenerator - - - IRaCIS .Core.IServiceAsync.cs - TextTemplatingFileGenerator - - - TextTemplatingFileGenerator - IRaCIS.Core.Dto.cs - - - TextTemplatingFileGenerator - IRaCIS.Core.Entity.cs - - + + + Always + + + Always + + + Always + + + IRaCIS .Core.ServiceAsync.cs + TextTemplatingFileGenerator + + + IRaCIS .Core.IServiceAsync.cs + TextTemplatingFileGenerator + + + TextTemplatingFileGenerator + IRaCIS.Core.Dto.cs + + + TextTemplatingFileGenerator + IRaCIS.Core.Entity.cs + + - - - + + + - - - IRaCIS .Core.IServiceAsync.tt - True - True - - - IRaCIS .Core.ServiceAsync.tt - True - True - - - True - True - IRaCIS.Core.Dto.tt - - - True - True - IRaCIS.Core.Entity.tt - - + + + IRaCIS .Core.IServiceAsync.tt + True + True + + + IRaCIS .Core.ServiceAsync.tt + True + True + + + True + True + IRaCIS.Core.Dto.tt + + + True + True + IRaCIS.Core.Entity.tt + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + - - - + + + diff --git a/IRaCIS.Core.Test/PGModelFolder/PGContext.cs b/IRaCIS.Core.Test/PGModelFolder/PGContext.cs new file mode 100644 index 000000000..73dffe521 --- /dev/null +++ b/IRaCIS.Core.Test/PGModelFolder/PGContext.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; + +namespace IRaCIS.Core.Test.PGModelFolder; + +public partial class PGContext : DbContext +{ + public PGContext() + { + } + + public PGContext(DbContextOptions options) + : base(options) + { + } + + public virtual DbSet Subjects { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.UseNpgsql("Host=106.14.89.110;Port=5432;Username=sa;Password=pgsql_pwd;Database=Test6_PG"); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + + if (base.Database.IsNpgsql()) + { + modelBuilder.HasPostgresExtension("uuid-ossp"); + + //保证pgsql 生成的时间默认为timestamp 而不是 timestamp with time zone + foreach (var entityType in modelBuilder.Model.GetEntityTypes()) + { + foreach (var property in entityType.GetProperties()) + { + if (property.ClrType == typeof(DateTime) || property.ClrType == typeof(DateTime?)) + { + property.SetColumnType("timestamp without time zone"); + } + } + } + } + + + + OnModelCreatingPartial(modelBuilder); + } + + partial void OnModelCreatingPartial(ModelBuilder modelBuilder); +} diff --git a/IRaCIS.Core.Test/PGModelFolder/Subject.cs b/IRaCIS.Core.Test/PGModelFolder/Subject.cs new file mode 100644 index 000000000..8ac7a14d8 --- /dev/null +++ b/IRaCIS.Core.Test/PGModelFolder/Subject.cs @@ -0,0 +1,84 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace IRaCIS.Core.Test.PGModelFolder; + +public partial class Subject +{ + public Guid Id { get; set; } + + [MaxLength(200)] + public string LastName { get; set; } + + public int StudyCount { get; set; } + + public DateTime? DeletedTime { get; set; } + + public DateTime? BirthDate { get; set; } + + public DateTime? FirstGiveMedicineTime { get; set; } + + public bool IsMissingImages { get; set; } + + public string MedicalNo { get; set; } + [MaxLength(200)] + public string ShortName { get; set; } + + public string Reason { get; set; } + + public Guid? FinalSubjectVisitId { get; set; } + + public string Height { get; set; } + + [Comment("subject 编号")] + [MaxLength(100)] + public string Code { get; set; } + + public int? Age { get; set; } + + public string Modalities { get; set; } + + public DateTime? SignDate { get; set; } + + public DateTime UpdateTime { get; set; } + + public Guid CreateUserId { get; set; } + + public string Sex { get; set; } + + public Guid? LatestSubjectVisitId { get; set; } + + public bool IsEnrollmentConfirm { get; set; } + + public Guid? DeleteUserId { get; set; } + + public string Weight { get; set; } + + public DateTime? OutEnrollmentTime { get; set; } + + public DateTime CreateTime { get; set; } + + public string FirstName { get; set; } + + public bool IsUrgent { get; set; } + + public long Status { get; set; } + + public DateTime? VisitOverTime { get; set; } + + public Guid UpdateUserId { get; set; } + + public bool IsDeleted { get; set; } + + public Guid TrialId { get; set; } + + public bool IsEnrollment { get; set; } + + public bool IsAssignDoctorUser { get; set; } + + public bool IsReReadingOrBackInfluenceAnalysis { get; set; } + + public Guid TrialSiteId { get; set; } +} diff --git a/IRaCIS.Core.Test/Program.cs b/IRaCIS.Core.Test/Program.cs index 6dd7114f1..38ddd3d4e 100644 --- a/IRaCIS.Core.Test/Program.cs +++ b/IRaCIS.Core.Test/Program.cs @@ -51,7 +51,7 @@ partial class Program // 要生成的表名数组 - var tableNames = new List { "Subject"/*, "Order"*/ }; + var tableNames = new List { /*"Subject", "Order"*/ }; try { diff --git a/IRaCIS.Core.Test/appsettings.json b/IRaCIS.Core.Test/appsettings.json new file mode 100644 index 000000000..fc7ead37a --- /dev/null +++ b/IRaCIS.Core.Test/appsettings.json @@ -0,0 +1,5 @@ +{ + "ConnectionStrings": { + "RemoteNew": "Server=106.14.89.110,1435;Database=Test_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true" + } +} \ No newline at end of file