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}
-
-
-
-
-
-
-
-
-
-
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}
-
-
-
-
-
-
-
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}
-
-
-
-
-
-
-
-
-
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}。
-
-
-
-
-
-
-
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}
-
-
-
-
-
-
-
-
-
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}
-
-
-
-
-
-
-
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}
-
-
-
-
-
-
-
-
-
-
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}
-
-
-
-
-
-
-
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}
-
-
-
-
- 登陆并查看
-
-
-
-
-
-
-
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}
-
-
-
-
-
-
-
-
-
-
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}
-
-
-
-
-
-
-
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}
-
-
-
-
-
-
-
-
-
-
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}
-
-
-
-
-
-
-
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分钟内输入该验证码,进行后续操作
-
-
-
-
-
-
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