From d36fef2bbbef107af8ce0a2dacf658e3349ca5f0 Mon Sep 17 00:00:00 2001
From: SpecialX <47072643+wangxiner55@users.noreply.github.com>
Date: Fri, 23 May 2025 19:03:00 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=A1=B9=E7=9B=AE=E6=96=87?=
=?UTF-8?q?=E4=BB=B6=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.dockerignore | 30 +
EmailLib/EmailConfiguration.cs | 12 +
EmailLib/EmailLib.csproj | 13 +
EmailLib/EmailTemap.cs | 109 ++
EmailLib/IEmailSender.cs | 18 +
EmailLib/QEmailSender.cs | 79 ++
Entities/Configuration/ApiConfiguration.cs | 7 +
Entities/Configuration/JwtConfiguration.cs | 10 +
Entities/Context/IPagedList.cs | 57 +
Entities/Context/PagedList.cs | 238 ++++
.../IEnumerablePagedListExtensions.cs | 39 +
.../IQueryablePageListExtensions.cs | 52 +
Entities/Context/UnitOfWork/IRepository.cs | 463 +++++++
.../Context/UnitOfWork/IRepositoryFactory.cs | 20 +
Entities/Context/UnitOfWork/IUnitOfWork.cs | 78 ++
Entities/Context/UnitOfWork/IUnitOfWorkOfT.cs | 27 +
Entities/Context/UnitOfWork/Repository.cs | 942 +++++++++++++++
Entities/Context/UnitOfWork/UnitOfWork.cs | 225 ++++
.../UnitOfWorkServiceCollectionExtensions.cs | 118 ++
Entities/Contracts/Assignment.cs | 63 +
Entities/Contracts/AssignmentAttachment.cs | 49 +
Entities/Contracts/AssignmentClass.cs | 36 +
Entities/Contracts/AssignmentGroup.cs | 59 +
Entities/Contracts/AssignmentQuestion.cs | 50 +
Entities/Contracts/Class.cs | 55 +
Entities/Contracts/ClassStudent.cs | 34 +
Entities/Contracts/ClassTeacher.cs | 27 +
Entities/Contracts/Question.cs | 99 ++
Entities/Contracts/Submission.cs | 80 ++
Entities/Contracts/SubmissionDetail.cs | 66 +
Entities/Contracts/User.cs | 47 +
Entities/DTO/ApiResponse.cs | 23 +
Entities/DTO/AuthResponseDto.cs | 12 +
Entities/DTO/ClassDto.cs | 21 +
Entities/DTO/ForgotPasswordDto.cs | 17 +
Entities/DTO/RefreshTokenDto.cs | 8 +
Entities/DTO/ResetPasswordDto.cs | 22 +
Entities/DTO/ResetPasswordResponseDto.cs | 14 +
Entities/DTO/ResponseDto.cs | 14 +
Entities/DTO/TwoFactorVerificationDto.cs | 17 +
Entities/DTO/UserForAuthenticationDto.cs | 12 +
Entities/DTO/UserForRegistrationDto.cs | 51 +
Entities/DTO/UserRegistrationToClassDto.cs | 18 +
Entities/Entities.csproj | 15 +
Entities/RequestFeatures/MetaData.cs | 12 +
Entities/RequestFeatures/ProductParameters.cs | 22 +
TechHelper.Client/AI/AIConfiguration.cs | 108 ++
TechHelper.Client/AI/AIModels.cs | 41 +
TechHelper.Client/AI/AiService.cs | 58 +
TechHelper.Client/AI/GLMZ1Api.cs | 217 ++++
TechHelper.Client/AI/IAIService.cs | 7 +
TechHelper.Client/App.razor | 25 +
.../AuthProviders/AuthStateProvider.cs | 64 +
.../AuthProviders/TestAuthStateProvider.cs | 23 +
TechHelper.Client/Exam/Exam.cs | 258 ++++
TechHelper.Client/Features/JWTParser.cs | 57 +
.../HttpInterceptorHandlerService.cs | 86 ++
.../HttpInterceptor/HttpResponseException.cs | 27 +
.../AuthenticationClientService.cs | 198 +++
.../IAuthenticationClientService.cs | 17 +
.../HttpRepository/RefreshTokenService.cs | 34 +
TechHelper.Client/Layout/LoginDisplay.razor | 19 +
TechHelper.Client/Layout/MainLayout.razor | 42 +
TechHelper.Client/Layout/MainLayout.razor.css | 85 ++
TechHelper.Client/Layout/NavBar.razor | 13 +
TechHelper.Client/Layout/NavMenu.razor | 52 +
TechHelper.Client/Layout/NavMenu.razor.css | 83 ++
.../Layout/RedirectToLogin.razor | 9 +
TechHelper.Client/Pages/AI/AIDialog.razor | 196 +++
TechHelper.Client/Pages/AccountView.razor | 10 +
TechHelper.Client/Pages/AuthLinks.razor | 26 +
TechHelper.Client/Pages/Authentication.razor | 7 +
.../Pages/Author/EmailConfirmation.razor | 11 +
.../Pages/Author/EmailConfirmation.razor.cs | 42 +
.../Pages/Author/ForgotPassword.razor | 38 +
.../Pages/Author/ForgotPassword.razor.cs | 30 +
TechHelper.Client/Pages/Author/Login.razor | 48 +
TechHelper.Client/Pages/Author/Login.razor.cs | 51 +
.../Pages/Author/Registration.razor | 100 ++
.../Pages/Author/Registration.razor.cs | 62 +
.../Pages/Author/ResetPassword.razor | 49 +
.../Pages/Author/ResetPassword.razor.cs | 55 +
.../Pages/Author/RoleDetailInfo.razor | 11 +
TechHelper.Client/Pages/Author/Signout.razor | 47 +
.../Pages/Author/TwoStepVerification.razor | 39 +
.../Pages/Author/TwoStepVerification.razor.cs | 60 +
.../Pages/Components/AssignmentView.razor | 81 ++
.../Pages/Components/ErrorDis.razor | 45 +
.../Pages/Components/Exam/Blank.razor | 33 +
.../Pages/Components/Exam/Blank.razor.css | 27 +
.../Pages/Components/Exam/CommonGroup.razor | 198 +++
.../Pages/Components/Exam/QuestionBase.razor | 98 ++
.../Components/Exam/QuestionTemplate.razor | 124 ++
.../Pages/Components/Exam/RadioChoice.razor | 165 +++
.../Pages/Components/GrageView.razor | 41 +
.../Pages/Components/HeaderLine.razor | 5 +
.../Pages/Components/UserBaseView.razor | 33 +
TechHelper.Client/Pages/Counter.razor | 18 +
.../Pages/Editor/EditorMain.razor | 113 ++
.../Pages/Editor/EditorMain.razor.cs | 214 ++++
TechHelper.Client/Pages/Editor/Test.razor | 50 +
.../Pages/ErrorHandle/Error.razor | 4 +
.../Pages/ErrorHandle/Notfound.razor | 8 +
.../Pages/ErrorHandle/Unauthorized.razor | 8 +
.../Pages/Exam/ChoiceQuestion.razor | 1 +
.../Pages/Exam/QuestionBase.razor | 11 +
.../Pages/Exam/QuestionGroup.razor | 4 +
.../Pages/Exam/QuestionGroupDisplay.razor | 73 ++
TechHelper.Client/Pages/Home.razor | 21 +
TechHelper.Client/Pages/Manage/Class.razor | 58 +
TechHelper.Client/Pages/Manage/Class.razor.cs | 62 +
TechHelper.Client/Pages/Manage/Index.razor | 60 +
.../Pages/Manage/PersonalData.razor | 30 +
TechHelper.Client/Pages/Manage/_Imports.razor | 2 +
TechHelper.Client/Pages/Weather.razor | 57 +
TechHelper.Client/Pages/_Imports.razor | 2 +
TechHelper.Client/Program.cs | 65 +
.../Properties/launchSettings.json | 31 +
TechHelper.Client/Services/ClasssServices.cs | 45 +
TechHelper.Client/Services/IClassServices.cs | 12 +
TechHelper.Client/Shared/AccountLayout.razor | 26 +
TechHelper.Client/Shared/ManageLayout.razor | 14 +
TechHelper.Client/Shared/ManageNavMenu.razor | 22 +
TechHelper.Client/TechHelper.Client.csproj | 33 +
TechHelper.Client/_Imports.razor | 22 +
.../wwwroot/appsettings.Development.json | 6 +
TechHelper.Client/wwwroot/appsettings.json | 9 +
TechHelper.Client/wwwroot/css/app.css | 103 ++
.../wwwroot/css/bootstrap/bootstrap.min.css | 7 +
.../css/bootstrap/bootstrap.min.css.map | 1 +
TechHelper.Client/wwwroot/favicon.png | Bin 0 -> 1148 bytes
TechHelper.Client/wwwroot/icon-192.png | Bin 0 -> 2626 bytes
TechHelper.Client/wwwroot/index.html | 40 +
.../wwwroot/sample-data/weather.json | 27 +
.../Context/ApplicationContext.cs | 41 +
.../Context/AutoMapperProFile.cs | 24 +
.../AssignmentAttachmentConfiguration.cs | 48 +
.../AssignmentClassConfiguration.cs | 50 +
.../Configuration/AssignmentConfiguration.cs | 82 ++
.../AssignmentGroupConfiguration.cs | 83 ++
.../AssignmentQuestionConfiguration.cs | 86 ++
.../Configuration/ClassConfiguration.cs | 99 ++
.../ClassStudentConfiguration.cs | 64 +
.../ClassTeacherConfiguration.cs | 61 +
.../Configuration/QuestionConfiguration.cs | 102 ++
.../Configuration/RoleConfiguration.cs | 25 +
.../Configuration/SubmissionConfiguration.cs | 109 ++
.../SubmissionDetailConfiguration.cs | 105 ++
.../Configuration/UserConfiguration.cs | 76 ++
.../Controllers/AccountController.cs | 287 +++++
.../Controllers/ClassController.cs | 43 +
.../Controllers/TokenController.cs | 65 +
.../Controllers/WeatherForecastController.cs | 33 +
TechHelper.Server/Dockerfile | 30 +
.../20250520094348_init.Designer.cs | 1075 +++++++++++++++++
.../Migrations/20250520094348_init.cs | 745 ++++++++++++
.../ApplicationContextModelSnapshot.cs | 1072 ++++++++++++++++
TechHelper.Server/Program.cs | 118 ++
.../Properties/launchSettings.json | 52 +
.../AssignmentAttachmentRepository.cs | 14 +
.../Repository/AssignmentClassRepository.cs | 14 +
.../Repository/AssignmentGroupRepository.cs | 14 +
.../AssignmentQuestionRepository.cs | 14 +
.../Repository/AssignmentRepository.cs | 14 +
.../Repository/ClassRepository.cs | 15 +
.../Repository/ClassStudentRepository.cs | 14 +
.../Repository/ClassTeacherRepository.cs | 14 +
.../Repository/QuestionRepository.cs | 14 +
.../Repository/SubmissionDetailRepository.cs | 14 +
.../Repository/SubmissionRepository.cs | 14 +
TechHelper.Server/Services/ApiResponse.cs | 23 +
.../Services/AuthenticationService.cs | 125 ++
TechHelper.Server/Services/ClassService.cs | 218 ++++
.../Services/IAuthenticationService.cs | 14 +
TechHelper.Server/Services/IBaseService.cs | 11 +
TechHelper.Server/Services/IClassService.cs | 12 +
.../Services/IUserRegistrationService.cs | 14 +
TechHelper.Server/Services/QueryParameter.cs | 9 +
.../Services/UserRegistrationService.cs | 126 ++
TechHelper.Server/TechHelper.Server.csproj | 35 +
TechHelper.Server/TechHelper.Server.http | 6 +
TechHelper.Server/WeatherForecast.cs | 13 +
.../appsettings.Development.json | 8 +
TechHelper.Server/appsettings.json | 27 +
TechHelper.sln | 48 +
185 files changed, 13413 insertions(+)
create mode 100644 .dockerignore
create mode 100644 EmailLib/EmailConfiguration.cs
create mode 100644 EmailLib/EmailLib.csproj
create mode 100644 EmailLib/EmailTemap.cs
create mode 100644 EmailLib/IEmailSender.cs
create mode 100644 EmailLib/QEmailSender.cs
create mode 100644 Entities/Configuration/ApiConfiguration.cs
create mode 100644 Entities/Configuration/JwtConfiguration.cs
create mode 100644 Entities/Context/IPagedList.cs
create mode 100644 Entities/Context/PagedList.cs
create mode 100644 Entities/Context/UnitOfWork/IEnumerablePagedListExtensions.cs
create mode 100644 Entities/Context/UnitOfWork/IQueryablePageListExtensions.cs
create mode 100644 Entities/Context/UnitOfWork/IRepository.cs
create mode 100644 Entities/Context/UnitOfWork/IRepositoryFactory.cs
create mode 100644 Entities/Context/UnitOfWork/IUnitOfWork.cs
create mode 100644 Entities/Context/UnitOfWork/IUnitOfWorkOfT.cs
create mode 100644 Entities/Context/UnitOfWork/Repository.cs
create mode 100644 Entities/Context/UnitOfWork/UnitOfWork.cs
create mode 100644 Entities/Context/UnitOfWork/UnitOfWorkServiceCollectionExtensions.cs
create mode 100644 Entities/Contracts/Assignment.cs
create mode 100644 Entities/Contracts/AssignmentAttachment.cs
create mode 100644 Entities/Contracts/AssignmentClass.cs
create mode 100644 Entities/Contracts/AssignmentGroup.cs
create mode 100644 Entities/Contracts/AssignmentQuestion.cs
create mode 100644 Entities/Contracts/Class.cs
create mode 100644 Entities/Contracts/ClassStudent.cs
create mode 100644 Entities/Contracts/ClassTeacher.cs
create mode 100644 Entities/Contracts/Question.cs
create mode 100644 Entities/Contracts/Submission.cs
create mode 100644 Entities/Contracts/SubmissionDetail.cs
create mode 100644 Entities/Contracts/User.cs
create mode 100644 Entities/DTO/ApiResponse.cs
create mode 100644 Entities/DTO/AuthResponseDto.cs
create mode 100644 Entities/DTO/ClassDto.cs
create mode 100644 Entities/DTO/ForgotPasswordDto.cs
create mode 100644 Entities/DTO/RefreshTokenDto.cs
create mode 100644 Entities/DTO/ResetPasswordDto.cs
create mode 100644 Entities/DTO/ResetPasswordResponseDto.cs
create mode 100644 Entities/DTO/ResponseDto.cs
create mode 100644 Entities/DTO/TwoFactorVerificationDto.cs
create mode 100644 Entities/DTO/UserForAuthenticationDto.cs
create mode 100644 Entities/DTO/UserForRegistrationDto.cs
create mode 100644 Entities/DTO/UserRegistrationToClassDto.cs
create mode 100644 Entities/Entities.csproj
create mode 100644 Entities/RequestFeatures/MetaData.cs
create mode 100644 Entities/RequestFeatures/ProductParameters.cs
create mode 100644 TechHelper.Client/AI/AIConfiguration.cs
create mode 100644 TechHelper.Client/AI/AIModels.cs
create mode 100644 TechHelper.Client/AI/AiService.cs
create mode 100644 TechHelper.Client/AI/GLMZ1Api.cs
create mode 100644 TechHelper.Client/AI/IAIService.cs
create mode 100644 TechHelper.Client/App.razor
create mode 100644 TechHelper.Client/AuthProviders/AuthStateProvider.cs
create mode 100644 TechHelper.Client/AuthProviders/TestAuthStateProvider.cs
create mode 100644 TechHelper.Client/Exam/Exam.cs
create mode 100644 TechHelper.Client/Features/JWTParser.cs
create mode 100644 TechHelper.Client/HttpInterceptor/HttpInterceptorHandlerService.cs
create mode 100644 TechHelper.Client/HttpInterceptor/HttpResponseException.cs
create mode 100644 TechHelper.Client/HttpRepository/AuthenticationClientService.cs
create mode 100644 TechHelper.Client/HttpRepository/IAuthenticationClientService.cs
create mode 100644 TechHelper.Client/HttpRepository/RefreshTokenService.cs
create mode 100644 TechHelper.Client/Layout/LoginDisplay.razor
create mode 100644 TechHelper.Client/Layout/MainLayout.razor
create mode 100644 TechHelper.Client/Layout/MainLayout.razor.css
create mode 100644 TechHelper.Client/Layout/NavBar.razor
create mode 100644 TechHelper.Client/Layout/NavMenu.razor
create mode 100644 TechHelper.Client/Layout/NavMenu.razor.css
create mode 100644 TechHelper.Client/Layout/RedirectToLogin.razor
create mode 100644 TechHelper.Client/Pages/AI/AIDialog.razor
create mode 100644 TechHelper.Client/Pages/AccountView.razor
create mode 100644 TechHelper.Client/Pages/AuthLinks.razor
create mode 100644 TechHelper.Client/Pages/Authentication.razor
create mode 100644 TechHelper.Client/Pages/Author/EmailConfirmation.razor
create mode 100644 TechHelper.Client/Pages/Author/EmailConfirmation.razor.cs
create mode 100644 TechHelper.Client/Pages/Author/ForgotPassword.razor
create mode 100644 TechHelper.Client/Pages/Author/ForgotPassword.razor.cs
create mode 100644 TechHelper.Client/Pages/Author/Login.razor
create mode 100644 TechHelper.Client/Pages/Author/Login.razor.cs
create mode 100644 TechHelper.Client/Pages/Author/Registration.razor
create mode 100644 TechHelper.Client/Pages/Author/Registration.razor.cs
create mode 100644 TechHelper.Client/Pages/Author/ResetPassword.razor
create mode 100644 TechHelper.Client/Pages/Author/ResetPassword.razor.cs
create mode 100644 TechHelper.Client/Pages/Author/RoleDetailInfo.razor
create mode 100644 TechHelper.Client/Pages/Author/Signout.razor
create mode 100644 TechHelper.Client/Pages/Author/TwoStepVerification.razor
create mode 100644 TechHelper.Client/Pages/Author/TwoStepVerification.razor.cs
create mode 100644 TechHelper.Client/Pages/Components/AssignmentView.razor
create mode 100644 TechHelper.Client/Pages/Components/ErrorDis.razor
create mode 100644 TechHelper.Client/Pages/Components/Exam/Blank.razor
create mode 100644 TechHelper.Client/Pages/Components/Exam/Blank.razor.css
create mode 100644 TechHelper.Client/Pages/Components/Exam/CommonGroup.razor
create mode 100644 TechHelper.Client/Pages/Components/Exam/QuestionBase.razor
create mode 100644 TechHelper.Client/Pages/Components/Exam/QuestionTemplate.razor
create mode 100644 TechHelper.Client/Pages/Components/Exam/RadioChoice.razor
create mode 100644 TechHelper.Client/Pages/Components/GrageView.razor
create mode 100644 TechHelper.Client/Pages/Components/HeaderLine.razor
create mode 100644 TechHelper.Client/Pages/Components/UserBaseView.razor
create mode 100644 TechHelper.Client/Pages/Counter.razor
create mode 100644 TechHelper.Client/Pages/Editor/EditorMain.razor
create mode 100644 TechHelper.Client/Pages/Editor/EditorMain.razor.cs
create mode 100644 TechHelper.Client/Pages/Editor/Test.razor
create mode 100644 TechHelper.Client/Pages/ErrorHandle/Error.razor
create mode 100644 TechHelper.Client/Pages/ErrorHandle/Notfound.razor
create mode 100644 TechHelper.Client/Pages/ErrorHandle/Unauthorized.razor
create mode 100644 TechHelper.Client/Pages/Exam/ChoiceQuestion.razor
create mode 100644 TechHelper.Client/Pages/Exam/QuestionBase.razor
create mode 100644 TechHelper.Client/Pages/Exam/QuestionGroup.razor
create mode 100644 TechHelper.Client/Pages/Exam/QuestionGroupDisplay.razor
create mode 100644 TechHelper.Client/Pages/Home.razor
create mode 100644 TechHelper.Client/Pages/Manage/Class.razor
create mode 100644 TechHelper.Client/Pages/Manage/Class.razor.cs
create mode 100644 TechHelper.Client/Pages/Manage/Index.razor
create mode 100644 TechHelper.Client/Pages/Manage/PersonalData.razor
create mode 100644 TechHelper.Client/Pages/Manage/_Imports.razor
create mode 100644 TechHelper.Client/Pages/Weather.razor
create mode 100644 TechHelper.Client/Pages/_Imports.razor
create mode 100644 TechHelper.Client/Program.cs
create mode 100644 TechHelper.Client/Properties/launchSettings.json
create mode 100644 TechHelper.Client/Services/ClasssServices.cs
create mode 100644 TechHelper.Client/Services/IClassServices.cs
create mode 100644 TechHelper.Client/Shared/AccountLayout.razor
create mode 100644 TechHelper.Client/Shared/ManageLayout.razor
create mode 100644 TechHelper.Client/Shared/ManageNavMenu.razor
create mode 100644 TechHelper.Client/TechHelper.Client.csproj
create mode 100644 TechHelper.Client/_Imports.razor
create mode 100644 TechHelper.Client/wwwroot/appsettings.Development.json
create mode 100644 TechHelper.Client/wwwroot/appsettings.json
create mode 100644 TechHelper.Client/wwwroot/css/app.css
create mode 100644 TechHelper.Client/wwwroot/css/bootstrap/bootstrap.min.css
create mode 100644 TechHelper.Client/wwwroot/css/bootstrap/bootstrap.min.css.map
create mode 100644 TechHelper.Client/wwwroot/favicon.png
create mode 100644 TechHelper.Client/wwwroot/icon-192.png
create mode 100644 TechHelper.Client/wwwroot/index.html
create mode 100644 TechHelper.Client/wwwroot/sample-data/weather.json
create mode 100644 TechHelper.Server/Context/ApplicationContext.cs
create mode 100644 TechHelper.Server/Context/AutoMapperProFile.cs
create mode 100644 TechHelper.Server/Context/Configuration/AssignmentAttachmentConfiguration.cs
create mode 100644 TechHelper.Server/Context/Configuration/AssignmentClassConfiguration.cs
create mode 100644 TechHelper.Server/Context/Configuration/AssignmentConfiguration.cs
create mode 100644 TechHelper.Server/Context/Configuration/AssignmentGroupConfiguration.cs
create mode 100644 TechHelper.Server/Context/Configuration/AssignmentQuestionConfiguration.cs
create mode 100644 TechHelper.Server/Context/Configuration/ClassConfiguration.cs
create mode 100644 TechHelper.Server/Context/Configuration/ClassStudentConfiguration.cs
create mode 100644 TechHelper.Server/Context/Configuration/ClassTeacherConfiguration.cs
create mode 100644 TechHelper.Server/Context/Configuration/QuestionConfiguration.cs
create mode 100644 TechHelper.Server/Context/Configuration/RoleConfiguration.cs
create mode 100644 TechHelper.Server/Context/Configuration/SubmissionConfiguration.cs
create mode 100644 TechHelper.Server/Context/Configuration/SubmissionDetailConfiguration.cs
create mode 100644 TechHelper.Server/Context/Configuration/UserConfiguration.cs
create mode 100644 TechHelper.Server/Controllers/AccountController.cs
create mode 100644 TechHelper.Server/Controllers/ClassController.cs
create mode 100644 TechHelper.Server/Controllers/TokenController.cs
create mode 100644 TechHelper.Server/Controllers/WeatherForecastController.cs
create mode 100644 TechHelper.Server/Dockerfile
create mode 100644 TechHelper.Server/Migrations/20250520094348_init.Designer.cs
create mode 100644 TechHelper.Server/Migrations/20250520094348_init.cs
create mode 100644 TechHelper.Server/Migrations/ApplicationContextModelSnapshot.cs
create mode 100644 TechHelper.Server/Program.cs
create mode 100644 TechHelper.Server/Properties/launchSettings.json
create mode 100644 TechHelper.Server/Repository/AssignmentAttachmentRepository.cs
create mode 100644 TechHelper.Server/Repository/AssignmentClassRepository.cs
create mode 100644 TechHelper.Server/Repository/AssignmentGroupRepository.cs
create mode 100644 TechHelper.Server/Repository/AssignmentQuestionRepository.cs
create mode 100644 TechHelper.Server/Repository/AssignmentRepository.cs
create mode 100644 TechHelper.Server/Repository/ClassRepository.cs
create mode 100644 TechHelper.Server/Repository/ClassStudentRepository.cs
create mode 100644 TechHelper.Server/Repository/ClassTeacherRepository.cs
create mode 100644 TechHelper.Server/Repository/QuestionRepository.cs
create mode 100644 TechHelper.Server/Repository/SubmissionDetailRepository.cs
create mode 100644 TechHelper.Server/Repository/SubmissionRepository.cs
create mode 100644 TechHelper.Server/Services/ApiResponse.cs
create mode 100644 TechHelper.Server/Services/AuthenticationService.cs
create mode 100644 TechHelper.Server/Services/ClassService.cs
create mode 100644 TechHelper.Server/Services/IAuthenticationService.cs
create mode 100644 TechHelper.Server/Services/IBaseService.cs
create mode 100644 TechHelper.Server/Services/IClassService.cs
create mode 100644 TechHelper.Server/Services/IUserRegistrationService.cs
create mode 100644 TechHelper.Server/Services/QueryParameter.cs
create mode 100644 TechHelper.Server/Services/UserRegistrationService.cs
create mode 100644 TechHelper.Server/TechHelper.Server.csproj
create mode 100644 TechHelper.Server/TechHelper.Server.http
create mode 100644 TechHelper.Server/WeatherForecast.cs
create mode 100644 TechHelper.Server/appsettings.Development.json
create mode 100644 TechHelper.Server/appsettings.json
create mode 100644 TechHelper.sln
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..fe1152b
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,30 @@
+**/.classpath
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/azds.yaml
+**/bin
+**/charts
+**/docker-compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
+!**/.gitignore
+!.git/HEAD
+!.git/config
+!.git/packed-refs
+!.git/refs/heads/**
\ No newline at end of file
diff --git a/EmailLib/EmailConfiguration.cs b/EmailLib/EmailConfiguration.cs
new file mode 100644
index 0000000..5d5c669
--- /dev/null
+++ b/EmailLib/EmailConfiguration.cs
@@ -0,0 +1,12 @@
+namespace TechHelper.Features
+{
+ public static class EmailConfiguration
+ {
+ public static string EmailFrom { get; set; } = "1468441589@qq.com";
+ public static string Password { get; set; } = "pfxhtoztjimtbahc";
+ public static string SubDescribe { get; set; } = "这是你的验证凭证";
+ public static string SmtpHost { get; set; } = "smtp.qq.com";
+ public static int SmtpPort { get; set; } = 587;
+
+ }
+}
diff --git a/EmailLib/EmailLib.csproj b/EmailLib/EmailLib.csproj
new file mode 100644
index 0000000..c1c0809
--- /dev/null
+++ b/EmailLib/EmailLib.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/EmailLib/EmailTemap.cs b/EmailLib/EmailTemap.cs
new file mode 100644
index 0000000..e442cf6
--- /dev/null
+++ b/EmailLib/EmailTemap.cs
@@ -0,0 +1,109 @@
+namespace Email
+{
+ public class EmailTemap
+ {
+ public static string _email = @"
+
+
+
+
+ {{AppName}} - Verification Code
+
+
+
+
+
+
您的验证码
+
+
您好,
+
+
您收到这封邮件是因为您请求验证您在 {{AppName}} 的邮箱地址。
+
请使用以下验证码完成操作:
+
+
+ {{VerificationCode}}
+
+
请在应用程序或网站中输入此验证码。
+
为了您的账户安全,请勿将此验证码透露给任何人。
+
此验证码在 {{ExpirationMinutes}} 分钟内有效。
+
如果您没有进行此操作,请忽略本邮件。
+
+
这是一封自动发送的邮件,请勿直接回复。
+
© {{AppName}}
+
支持: Tech Helper
+
+
+
+";
+
+
+
+
+
+ }
+}
\ No newline at end of file
diff --git a/EmailLib/IEmailSender.cs b/EmailLib/IEmailSender.cs
new file mode 100644
index 0000000..c4674b3
--- /dev/null
+++ b/EmailLib/IEmailSender.cs
@@ -0,0 +1,18 @@
+namespace TechHelper.Features
+{
+ public interface IEmailSender
+ {
+ ///
+ /// 使用 MailKit 通过邮箱发送邮件
+ ///
+ /// 收件人邮箱地址
+ /// 邮件主题
+ /// 邮件正文 (支持 HTML)
+ ///
+ public Task SendEmailAsync(string toEmail,string subject, string body);
+
+ public Task SendEmailAsync(string toEmail, string body);
+
+ public Task SendEmailAuthcodeAsync(string toEmail, string authCode);
+ }
+}
diff --git a/EmailLib/QEmailSender.cs b/EmailLib/QEmailSender.cs
new file mode 100644
index 0000000..d3e7b46
--- /dev/null
+++ b/EmailLib/QEmailSender.cs
@@ -0,0 +1,79 @@
+using MailKit.Net.Smtp;
+using MailKit.Security;
+using MimeKit;
+using Email;
+using System.Text;
+
+namespace TechHelper.Features
+{
+ public class QEmailSender : IEmailSender
+ {
+ public async Task SendEmailAsync(string toEmail, string subject, string body)
+ {
+ var secureSocketOption = SecureSocketOptions.StartTls;
+ try
+ {
+ var message = new MimeMessage();
+ message.From.Add(new MailboxAddress("TechHelper", EmailConfiguration.EmailFrom));
+ message.To.Add(new MailboxAddress("", toEmail));
+ message.Subject = subject;
+ message.Body = new TextPart(MimeKit.Text.TextFormat.Html)
+ {
+ Text = body
+ };
+
+
+ using (var client = new SmtpClient())
+ {
+ await client.ConnectAsync(EmailConfiguration.SmtpHost, EmailConfiguration.SmtpPort, secureSocketOption);
+
+ // 移除 XOAUTH2 认证机制,避免某些环境下出现异常
+ // 如果不加这行,某些情况下可能会遇到 MailKit.Security.AuthenticationException: XOAUTH2 is not supported
+ client.AuthenticationMechanisms.Remove("XOAUTH2");
+
+ await client.AuthenticateAsync(EmailConfiguration.EmailFrom, EmailConfiguration.Password);
+ await client.SendAsync(message);
+ await client.DisconnectAsync(true);
+ }
+
+ Console.WriteLine("邮件发送成功 (QQ 邮箱)!");
+ }
+ catch (TypeInitializationException ex)
+ {
+ Console.WriteLine("捕获到 SmtpClient 的 TypeInitializationException!");
+ Console.WriteLine($"异常消息: {ex.Message}");
+
+ Exception? inner = ex.InnerException; // 获取第一层内部异常
+ int innerCount = 1;
+ while (inner != null)
+ {
+ Console.WriteLine($"--> 内部异常 {innerCount}: {inner.GetType().Name}");
+ Console.WriteLine($"--> 内部异常消息: {inner.Message}");
+ inner = inner.InnerException; // 获取下一层内部异常
+ innerCount++;
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"捕获到其他类型的异常: {ex.GetType().Name}");
+ Console.WriteLine($"异常消息: {ex.Message}");
+ }
+ }
+
+ public async Task SendEmailAsync(string toEmail , string body)
+ {
+ await SendEmailAsync(toEmail, EmailConfiguration.SubDescribe, body);
+ }
+
+ public async Task SendEmailAuthcodeAsync(string toEmail, string authCode)
+ {
+ string htmlTemplateString = EmailTemap._email;
+ string htmlBody = htmlTemplateString
+ .Replace("{{AppName}}", "TechHelper")
+ .Replace("{{VerificationCode}}", authCode)
+ .Replace("{{ExpirationMinutes}}", "30")
+ .Replace("{{SupportEmail}}", "TechHelper");
+ await SendEmailAsync(toEmail, htmlBody);
+ }
+ }
+}
diff --git a/Entities/Configuration/ApiConfiguration.cs b/Entities/Configuration/ApiConfiguration.cs
new file mode 100644
index 0000000..9f9582a
--- /dev/null
+++ b/Entities/Configuration/ApiConfiguration.cs
@@ -0,0 +1,7 @@
+namespace Entities.Configuration
+{
+ public class ApiConfiguration
+ {
+ public string? BaseAddress { get; set; } /*= "http://localhost:5099";*/
+ }
+}
diff --git a/Entities/Configuration/JwtConfiguration.cs b/Entities/Configuration/JwtConfiguration.cs
new file mode 100644
index 0000000..86b6ad1
--- /dev/null
+++ b/Entities/Configuration/JwtConfiguration.cs
@@ -0,0 +1,10 @@
+namespace Entities.Configuration
+{
+ public class JwtConfiguration
+ {
+ public string? SecurityKey { get; set; }
+ public string? ValidIssuer { get; set; }
+ public string? ValidAudience { get; set; }
+ public int ExpiryInMinutes { get; set; }
+ }
+}
diff --git a/Entities/Context/IPagedList.cs b/Entities/Context/IPagedList.cs
new file mode 100644
index 0000000..1318bfe
--- /dev/null
+++ b/Entities/Context/IPagedList.cs
@@ -0,0 +1,57 @@
+namespace SharedDATA.Context
+{
+
+ using System.Collections.Generic;
+ ///
+ /// Provides the interface(s) for paged list of any type.
+ /// 为任何类型的分页列表提供接口
+ ///
+ /// The type for paging.分页的类型
+ public interface IPagedList
+ {
+ ///
+ /// Gets the index start value.
+ /// 获取索引起始值
+ ///
+ /// The index start value.
+ int IndexFrom { get; }
+ ///
+ /// Gets the page index (current).
+ /// 获取页索引(当前)
+ ///
+ int PageIndex { get; }
+ ///
+ /// Gets the page size.
+ /// 获取页面大小
+ ///
+ int PageSize { get; }
+ ///
+ /// Gets the total count of the list of type
+ /// 获取类型列表的总计数
+ ///
+ int TotalCount { get; }
+ ///
+ /// Gets the total pages.
+ /// 获取页面总数
+ ///
+ int TotalPages { get; }
+ ///
+ /// Gets the current page items.
+ /// 获取当前页项
+ ///
+ IList Items { get; }
+ ///
+ /// Gets the has previous page.
+ /// 获取前一页
+ ///
+ /// The has previous page.
+ bool HasPreviousPage { get; }
+
+ ///
+ /// Gets the has next page.
+ /// 获取下一页
+ ///
+ /// The has next page.
+ bool HasNextPage { get; }
+ }
+}
diff --git a/Entities/Context/PagedList.cs b/Entities/Context/PagedList.cs
new file mode 100644
index 0000000..fe70f31
--- /dev/null
+++ b/Entities/Context/PagedList.cs
@@ -0,0 +1,238 @@
+namespace SharedDATA.Context
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+
+ ///
+ /// Represents the default implementation of the interface.
+ ///
+ /// The type of the data to page 页类型的数据
+ public class PagedList : IPagedList
+ {
+ ///
+ /// Gets or sets the index of the page.
+ /// 获得页的起始页
+ ///
+ /// The index of the page.
+ public int PageIndex { get; set; }
+ ///
+ /// Gets or sets the size of the page.
+ /// 获得页大小
+ ///
+ /// The size of the page.
+ public int PageSize { get; set; }
+ ///
+ /// Gets or sets the total count.
+ /// 获得总数
+ ///
+ /// The total count.
+ public int TotalCount { get; set; }
+ ///
+ /// Gets or sets the total pages.
+ /// 获得总页数
+ ///
+ /// The total pages.
+ public int TotalPages { get; set; }
+ ///
+ /// Gets or sets the index from.
+ /// 从索引起
+ ///
+ /// The index from.
+ public int IndexFrom { get; set; }
+
+ ///
+ /// Gets or sets the items.
+ /// 数据
+ ///
+ /// The items.
+ public IList Items { get; set; }
+
+ ///
+ /// Gets the has previous page.
+ /// 获取前一页
+ ///
+ /// The has previous page.
+ public bool HasPreviousPage => PageIndex - IndexFrom > 0;
+
+ ///
+ /// Gets the has next page.
+ /// 获取下一页
+ ///
+ /// The has next page.
+ public bool HasNextPage => PageIndex - IndexFrom + 1 < TotalPages;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The source.
+ /// The index of the page.
+ /// The size of the page.
+ /// The index from.
+ public PagedList(IEnumerable source, int pageIndex, int pageSize, int indexFrom)
+ {
+ if (indexFrom > pageIndex)
+ {
+ throw new ArgumentException($"indexFrom: {indexFrom} > pageIndex: {pageIndex}, must indexFrom <= pageIndex");
+ }
+
+ if (source is IQueryable querable)
+ {
+ PageIndex = pageIndex;
+ PageSize = pageSize;
+ IndexFrom = indexFrom;
+ TotalCount = querable.Count();
+ TotalPages = (int)Math.Ceiling(TotalCount / (double)PageSize);
+
+ Items = querable.Skip((PageIndex - IndexFrom) * PageSize).Take(PageSize).ToList();
+ }
+ else
+ {
+ PageIndex = pageIndex;
+ PageSize = pageSize;
+ IndexFrom = indexFrom;
+ TotalCount = source.Count();
+ TotalPages = (int)Math.Ceiling(TotalCount / (double)PageSize);
+
+ Items = source.Skip((PageIndex - IndexFrom) * PageSize).Take(PageSize).ToList();
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PagedList() => Items = new T[0];
+ }
+
+
+ ///
+ /// Provides the implementation of the and converter.
+ ///
+ /// The type of the source.
+ /// The type of the result.
+ public class PagedList : IPagedList
+ {
+ ///
+ /// Gets the index of the page.
+ ///
+ /// The index of the page.
+ public int PageIndex { get; }
+ ///
+ /// Gets the size of the page.
+ ///
+ /// The size of the page.
+ public int PageSize { get; }
+ ///
+ /// Gets the total count.
+ ///
+ /// The total count.
+ public int TotalCount { get; }
+ ///
+ /// Gets the total pages.
+ ///
+ /// The total pages.
+ public int TotalPages { get; }
+ ///
+ /// Gets the index from.
+ ///
+ /// The index from.
+ public int IndexFrom { get; }
+
+ ///
+ /// Gets the items.
+ ///
+ /// The items.
+ public IList Items { get; }
+
+ ///
+ /// Gets the has previous page.
+ ///
+ /// The has previous page.
+ public bool HasPreviousPage => PageIndex - IndexFrom > 0;
+
+ ///
+ /// Gets the has next page.
+ ///
+ /// The has next page.
+ public bool HasNextPage => PageIndex - IndexFrom + 1 < TotalPages;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The source.
+ /// The converter.
+ /// The index of the page.
+ /// The size of the page.
+ /// The index from.
+ public PagedList(IEnumerable source, Func, IEnumerable> converter, int pageIndex, int pageSize, int indexFrom)
+ {
+ if (indexFrom > pageIndex)
+ {
+ throw new ArgumentException($"indexFrom: {indexFrom} > pageIndex: {pageIndex}, must indexFrom <= pageIndex");
+ }
+
+ if (source is IQueryable querable)
+ {
+ PageIndex = pageIndex;
+ PageSize = pageSize;
+ IndexFrom = indexFrom;
+ TotalCount = querable.Count();
+ TotalPages = (int)Math.Ceiling(TotalCount / (double)PageSize);
+
+ var items = querable.Skip((PageIndex - IndexFrom) * PageSize).Take(PageSize).ToArray();
+
+ Items = new List(converter(items));
+ }
+ else
+ {
+ PageIndex = pageIndex;
+ PageSize = pageSize;
+ IndexFrom = indexFrom;
+ TotalCount = source.Count();
+ TotalPages = (int)Math.Ceiling(TotalCount / (double)PageSize);
+
+ var items = source.Skip((PageIndex - IndexFrom) * PageSize).Take(PageSize).ToArray();
+
+ Items = new List(converter(items));
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The source.
+ /// The converter.
+ public PagedList(IPagedList source, Func, IEnumerable> converter)
+ {
+ PageIndex = source.PageIndex;
+ PageSize = source.PageSize;
+ IndexFrom = source.IndexFrom;
+ TotalCount = source.TotalCount;
+ TotalPages = source.TotalPages;
+
+ Items = new List(converter(source.Items));
+ }
+ }
+
+ ///
+ /// Provides some help methods for interface.
+ ///
+ public static class PagedList
+ {
+ ///
+ /// Creates an empty of .
+ ///
+ /// The type for paging
+ /// An empty instance of .
+ public static IPagedList Empty() => new PagedList();
+ ///
+ /// Creates a new instance of from source of instance.
+ ///
+ /// The type of the result.
+ /// The type of the source.
+ /// The source.
+ /// The converter.
+ /// An instance of .
+ public static IPagedList From(IPagedList source, Func, IEnumerable> converter) => new PagedList(source, converter);
+ }
+}
diff --git a/Entities/Context/UnitOfWork/IEnumerablePagedListExtensions.cs b/Entities/Context/UnitOfWork/IEnumerablePagedListExtensions.cs
new file mode 100644
index 0000000..a19848e
--- /dev/null
+++ b/Entities/Context/UnitOfWork/IEnumerablePagedListExtensions.cs
@@ -0,0 +1,39 @@
+namespace SharedDATA.Api
+{
+ using SharedDATA.Context;
+ using System;
+ using System.Collections.Generic;
+
+ ///
+ /// Provides some extension methods for to provide paging capability.
+ /// 提供一些扩展方法来提供分页功能
+ ///
+ public static class IEnumerablePagedListExtensions
+ {
+ ///
+ /// Converts the specified source to by the specified and .
+ /// 通过起始页和页大小把数据转换成页集合
+ ///
+ /// The type of the source.源的类型
+ /// The source to paging.分页的源
+ /// The index of the page.起始页
+ /// The size of the page.页大小
+ /// The start index value.开始索引值
+ /// An instance of the inherited from interface.接口继承的实例
+ public static IPagedList ToPagedList(this IEnumerable source, int pageIndex, int pageSize, int indexFrom = 0) => new PagedList(source, pageIndex, pageSize, indexFrom);
+
+ ///
+ /// Converts the specified source to by the specified , and
+ /// 通过转换器,起始页和页大小把数据转换成页集合
+ ///
+ /// The type of the source.源的类型
+ /// The type of the result.反馈的类型
+ /// The source to convert.要转换的源
+ /// The converter to change the to .转换器来改变源到反馈
+ /// The page index.起始页
+ /// The page size.页大小
+ /// The start index value.开始索引值
+ /// An instance of the inherited from interface.接口继承的实例
+ public static IPagedList ToPagedList(this IEnumerable source, Func, IEnumerable> converter, int pageIndex, int pageSize, int indexFrom = 0) => new PagedList(source, converter, pageIndex, pageSize, indexFrom);
+ }
+}
diff --git a/Entities/Context/UnitOfWork/IQueryablePageListExtensions.cs b/Entities/Context/UnitOfWork/IQueryablePageListExtensions.cs
new file mode 100644
index 0000000..046589e
--- /dev/null
+++ b/Entities/Context/UnitOfWork/IQueryablePageListExtensions.cs
@@ -0,0 +1,52 @@
+namespace SharedDATA.Api
+{
+ using System;
+ using System.Linq;
+ using System.Threading;
+ using System.Threading.Tasks;
+ using Microsoft.EntityFrameworkCore;
+ using SharedDATA.Context;
+
+ public static class IQueryablePageListExtensions
+ {
+ ///
+ /// Converts the specified source to by the specified and .
+ /// 根据起始页和页大小转换成源
+ ///
+ /// The type of the source.源的类型
+ /// The source to paging.分页的源
+ /// The index of the page.起始页
+ /// The size of the page.页大小
+ ///
+ /// A to observe while waiting for the task to complete.
+ /// 在等待任务完成时观察
+ ///
+ /// The start index value.值的起始索引
+ /// An instance of the inherited from interface.接口继承的实例
+ public static async Task> ToPagedListAsync(this IQueryable source, int pageIndex, int pageSize, int indexFrom = 0, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ //如果索引比起始页大,则异常
+ if (indexFrom > pageIndex)
+ {
+ throw new ArgumentException($"indexFrom: {indexFrom} > pageIndex: {pageIndex}, must indexFrom <= pageIndex");
+ }
+ //数据源大小
+ var count = await source.CountAsync(cancellationToken).ConfigureAwait(false);
+
+ var items = await source.Skip((pageIndex - indexFrom) * pageSize)
+ .Take(pageSize).ToListAsync(cancellationToken).ConfigureAwait(false);
+
+ var pagedList = new PagedList()
+ {
+ PageIndex = pageIndex,
+ PageSize = pageSize,
+ IndexFrom = indexFrom,
+ TotalCount = count,
+ Items = items,
+ TotalPages = (int)Math.Ceiling(count / (double)pageSize)
+ };
+
+ return pagedList;
+ }
+ }
+}
diff --git a/Entities/Context/UnitOfWork/IRepository.cs b/Entities/Context/UnitOfWork/IRepository.cs
new file mode 100644
index 0000000..b397860
--- /dev/null
+++ b/Entities/Context/UnitOfWork/IRepository.cs
@@ -0,0 +1,463 @@
+namespace SharedDATA.Api
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Linq.Expressions;
+ using System.Threading;
+ using System.Threading.Tasks;
+ using Microsoft.EntityFrameworkCore.Query;
+ using Microsoft.EntityFrameworkCore.ChangeTracking;
+ using Microsoft.EntityFrameworkCore;
+ using SharedDATA.Context;
+
+ ///
+ /// Defines the interfaces for generic repository.
+ /// 为通用存储库定义接口
+ ///
+ /// The type of the entity.实体类型
+ public interface IRepository where TEntity : class
+ {
+ ///
+ /// Changes the table name. This require the tables in the same database.
+ /// 更改表名。这需要相同数据库中的表
+ ///
+ ///
+ ///
+ /// This only been used for supporting multiple tables in the same model. This require the tables in the same database.
+ /// 这只用于支持同一个模型中的多个表。这需要相同数据库中的表。
+ ///
+ void ChangeTable(string table);
+
+ ///
+ /// Gets the based on a predicate, orderby delegate and page information. This method default no-tracking query.
+ /// 基于谓词、orderby委托和页面信息获取。此方法默认无跟踪查询。
+ ///
+ /// A function to test each element for a condition.用于测试条件的每个元素的函数
+ /// A function to order elements.对元素进行排序的函数
+ /// A function to include navigation properties 包含导航属性的函数
+ /// The index of page.起始页
+ /// The size of the page.页大小
+ /// True to disable changing tracking; otherwise, 禁用更改跟踪false. Default to true.
+ /// Ignore query filters 忽略查询过滤器
+ /// An that contains elements that satisfy the condition specified by 包含满足指定条件的元素.
+ /// This method default no-tracking query.
+ IPagedList GetPagedList(Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ int pageIndex = 0,
+ int pageSize = 20,
+ bool disableTracking = true,
+ bool ignoreQueryFilters = false);
+
+ ///
+ /// Gets the based on a predicate, orderby delegate and page information. This method default no-tracking query.
+ /// 基于谓词、orderby委托和页面信息获取。此方法默认无跟踪查询。
+ ///
+ /// A function to test each element for a condition.用于测试条件的每个元素的函数
+ /// A function to order elements.对元素进行排序的函数
+ /// A function to include navigation properties 包含导航属性的函数
+ /// The index of page.起始页
+ /// The size of the page.页大小
+ /// True to disable changing tracking;禁用更改跟踪; otherwise, false. Default to true.
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ /// Ignore query filters 忽略查询过滤器
+ /// An that contains elements that satisfy the condition specified by .
+ /// This method default no-tracking query.此方法默认无跟踪查询
+ Task> GetPagedListAsync(Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ int pageIndex = 0,
+ int pageSize = 20,
+ bool disableTracking = true,
+ CancellationToken cancellationToken = default(CancellationToken),
+ bool ignoreQueryFilters = false);
+
+ ///
+ /// Gets the based on a predicate, orderby delegate and page information. This method default no-tracking query.
+ ///
+ /// The selector for projection.
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// The index of page.
+ /// The size of the page.
+ /// True to disable changing tracking; otherwise, false. Default to true.
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// This method default no-tracking query.
+ IPagedList GetPagedList(Expression> selector,
+ Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ int pageIndex = 0,
+ int pageSize = 20,
+ bool disableTracking = true,
+ bool ignoreQueryFilters = false) where TResult : class;
+
+ ///
+ /// Gets the based on a predicate, orderby delegate and page information. This method default no-tracking query.
+ ///
+ /// The selector for projection.
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// The index of page.
+ /// The size of the page.
+ /// True to disable changing tracking; otherwise, false. Default to true.
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// This method default no-tracking query.
+ Task> GetPagedListAsync(Expression> selector,
+ Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ int pageIndex = 0,
+ int pageSize = 20,
+ bool disableTracking = true,
+ CancellationToken cancellationToken = default(CancellationToken),
+ bool ignoreQueryFilters = false) where TResult : class;
+
+ ///
+ /// Gets the first or default entity based on a predicate, orderby delegate and include delegate. This method defaults to a read-only, no-tracking query.
+ ///
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// true to disable changing tracking; otherwise, false. Default to true.
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// This method defaults to a read-only, no-tracking query.
+ TEntity GetFirstOrDefault(Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ bool disableTracking = true,
+ bool ignoreQueryFilters = false);
+
+ ///
+ /// Gets the first or default entity based on a predicate, orderby delegate and include delegate. This method defaults to a read-only, no-tracking query.
+ ///
+ /// The selector for projection.
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// true to disable changing tracking; otherwise, false. Default to true.
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// This method defaults to a read-only, no-tracking query.
+ TResult GetFirstOrDefault(Expression> selector,
+ Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ bool disableTracking = true,
+ bool ignoreQueryFilters = false);
+
+ ///
+ /// Gets the first or default entity based on a predicate, orderby delegate and include delegate. This method defaults to a read-only, no-tracking query.
+ ///
+ /// The selector for projection.
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// true to disable changing tracking; otherwise, false. Default to true.
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// Ex: This method defaults to a read-only, no-tracking query.
+ Task GetFirstOrDefaultAsync(Expression> selector,
+ Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ bool disableTracking = true,
+ bool ignoreQueryFilters = false);
+
+ ///
+ /// Gets the first or default entity based on a predicate, orderby delegate and include delegate. This method defaults to a read-only, no-tracking query.
+ ///
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// true to disable changing tracking; otherwise, false. Default to true.
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// Ex: This method defaults to a read-only, no-tracking query.
+ Task GetFirstOrDefaultAsync(Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ bool disableTracking = true,
+ bool ignoreQueryFilters = false);
+
+ ///
+ /// Uses raw SQL queries to fetch the specified data.
+ ///
+ /// The raw SQL.
+ /// The parameters.
+ /// An that contains elements that satisfy the condition specified by raw SQL.
+ IQueryable FromSql(string sql, params object[] parameters);
+
+ ///
+ /// Finds an entity with the given primary key values. If found, is attached to the context and returned. If no entity is found, then null is returned.
+ ///
+ /// The values of the primary key for the entity to be found.
+ /// The found entity or null.
+ TEntity Find(params object[] keyValues);
+
+ ///
+ /// Finds an entity with the given primary key values. If found, is attached to the context and returned. If no entity is found, then null is returned.
+ ///
+ /// The values of the primary key for the entity to be found.
+ /// A that represents the asynchronous find operation. The task result contains the found entity or null.
+ ValueTask FindAsync(params object[] keyValues);
+
+ ///
+ /// Finds an entity with the given primary key values. If found, is attached to the context and returned. If no entity is found, then null is returned.
+ ///
+ /// The values of the primary key for the entity to be found.
+ /// A to observe while waiting for the task to complete.
+ /// A that represents the asynchronous find operation. The task result contains the found entity or null.
+ ValueTask FindAsync(object[] keyValues, CancellationToken cancellationToken);
+
+ ///
+ /// Gets all entities. This method is not recommended
+ ///
+ /// The .
+ IQueryable GetAll();
+
+ ///
+ /// Gets all entities. This method is not recommended
+ ///
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// true to disable changing tracking; otherwise, false. Default to true.
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// Ex: This method defaults to a read-only, no-tracking query.
+ IQueryable GetAll(Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ bool disableTracking = true,
+ bool ignoreQueryFilters = false);
+
+ ///
+ /// Gets all entities. This method is not recommended
+ ///
+ /// The .
+ Task> GetAllAsync();
+
+ ///
+ /// Gets all entities. This method is not recommended
+ ///
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// true to disable changing tracking; otherwise, false. Default to true.
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// Ex: This method defaults to a read-only, no-tracking query.
+ Task> GetAllAsync(Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ bool disableTracking = true,
+ bool ignoreQueryFilters = false);
+
+ ///
+ /// Gets the count based on a predicate.
+ ///
+ ///
+ ///
+ int Count(Expression> predicate = null);
+
+ ///
+ /// Gets async the count based on a predicate.
+ ///
+ ///
+ ///
+ Task CountAsync(Expression> predicate = null);
+
+ ///
+ /// Gets the long count based on a predicate.
+ ///
+ ///
+ ///
+ long LongCount(Expression> predicate = null);
+
+ ///
+ /// Gets async the long count based on a predicate.
+ ///
+ ///
+ ///
+ Task LongCountAsync(Expression> predicate = null);
+
+ ///
+ /// Gets the max based on a predicate.
+ ///
+ ///
+ /// ///
+ /// decimal
+ T Max(Expression> predicate = null, Expression> selector = null);
+
+ ///
+ /// Gets the async max based on a predicate.
+ ///
+ ///
+ /// ///
+ /// decimal
+ Task MaxAsync(Expression> predicate = null, Expression> selector = null);
+
+ ///
+ /// Gets the min based on a predicate.
+ ///
+ ///
+ ///
+ /// decimal
+ T Min(Expression> predicate = null, Expression> selector = null);
+
+ ///
+ /// Gets the async min based on a predicate.
+ ///
+ ///
+ ///
+ /// decimal
+ Task MinAsync(Expression> predicate = null, Expression> selector = null);
+
+ ///
+ /// Gets the average based on a predicate.
+ ///
+ ///
+ /// ///
+ /// decimal
+ decimal Average(Expression> predicate = null, Expression> selector = null);
+
+ ///
+ /// Gets the async average based on a predicate.
+ ///
+ ///
+ /// ///
+ /// decimal
+ Task AverageAsync(Expression> predicate = null, Expression> selector = null);
+
+ ///
+ /// Gets the sum based on a predicate.
+ ///
+ ///
+ /// ///
+ /// decimal
+ decimal Sum(Expression> predicate = null, Expression> selector = null);
+
+ ///
+ /// Gets the async sum based on a predicate.
+ ///
+ ///
+ /// ///
+ /// decimal
+ Task SumAsync(Expression> predicate = null, Expression> selector = null);
+
+ ///
+ /// Gets the Exists record based on a predicate.
+ ///
+ ///
+ ///
+ bool Exists(Expression> selector = null);
+ ///
+ /// Gets the Async Exists record based on a predicate.
+ ///
+ ///
+ ///
+ Task ExistsAsync(Expression> selector = null);
+
+ ///
+ /// Inserts a new entity synchronously.
+ ///
+ /// The entity to insert.
+ TEntity Insert(TEntity entity);
+
+ ///
+ /// Inserts a range of entities synchronously.
+ ///
+ /// The entities to insert.
+ void Insert(params TEntity[] entities);
+
+ ///
+ /// Inserts a range of entities synchronously.
+ ///
+ /// The entities to insert.
+ void Insert(IEnumerable entities);
+
+ ///
+ /// Inserts a new entity asynchronously.
+ ///
+ /// The entity to insert.
+ /// A to observe while waiting for the task to complete.
+ /// A that represents the asynchronous insert operation.
+ ValueTask> InsertAsync(TEntity entity, CancellationToken cancellationToken = default(CancellationToken));
+
+ ///
+ /// Inserts a range of entities asynchronously.
+ ///
+ /// The entities to insert.
+ /// A that represents the asynchronous insert operation.
+ Task InsertAsync(params TEntity[] entities);
+
+ ///
+ /// Inserts a range of entities asynchronously.
+ ///
+ /// The entities to insert.
+ /// A to observe while waiting for the task to complete.
+ /// A that represents the asynchronous insert operation.
+ Task InsertAsync(IEnumerable entities, CancellationToken cancellationToken = default(CancellationToken));
+
+ ///
+ /// Updates the specified entity.
+ ///
+ /// The entity.
+ void Update(TEntity entity);
+
+ ///
+ /// Updates the specified entities.
+ ///
+ /// The entities.
+ void Update(params TEntity[] entities);
+
+ ///
+ /// Updates the specified entities.
+ ///
+ /// The entities.
+ void Update(IEnumerable entities);
+
+ ///
+ /// Deletes the entity by the specified primary key.
+ ///
+ /// The primary key value.
+ void Delete(object id);
+
+ ///
+ /// Deletes the specified entity.
+ ///
+ /// The entity to delete.
+ void Delete(TEntity entity);
+
+ ///
+ /// Deletes the specified entities.
+ ///
+ /// The entities.
+ void Delete(params TEntity[] entities);
+
+ ///
+ /// Deletes the specified entities.
+ ///
+ /// The entities.
+ void Delete(IEnumerable entities);
+
+ ///
+ /// Change entity state for patch method on web api.
+ ///
+ /// The entity.
+ /// /// The entity state.
+ void ChangeEntityState(TEntity entity, EntityState state);
+ }
+}
diff --git a/Entities/Context/UnitOfWork/IRepositoryFactory.cs b/Entities/Context/UnitOfWork/IRepositoryFactory.cs
new file mode 100644
index 0000000..127e67e
--- /dev/null
+++ b/Entities/Context/UnitOfWork/IRepositoryFactory.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SharedDATA.Api
+{
+ ///
+ /// Defines the interfaces for interfaces.
+ ///
+ public interface IRepositoryFactory
+ {
+ ///
+ /// Gets the specified repository for the .
+ ///
+ /// True if providing custom repositry
+ /// The type of the entity.
+ /// An instance of type inherited from interface.
+ IRepository GetRepository(bool hasCustomRepository = false) where TEntity : class;
+ }
+}
diff --git a/Entities/Context/UnitOfWork/IUnitOfWork.cs b/Entities/Context/UnitOfWork/IUnitOfWork.cs
new file mode 100644
index 0000000..35293f6
--- /dev/null
+++ b/Entities/Context/UnitOfWork/IUnitOfWork.cs
@@ -0,0 +1,78 @@
+
+
+namespace SharedDATA.Api
+{
+ using System;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.EntityFrameworkCore;
+ using Microsoft.EntityFrameworkCore.ChangeTracking;
+
+ ///
+ /// Defines the interface(s) for unit of work.
+ ///
+ public interface IUnitOfWork : IDisposable
+ {
+
+ ///
+ /// Changes the database name. This require the databases in the same machine. NOTE: This only work for MySQL right now.
+ ///
+ /// The database name.
+ ///
+ /// This only been used for supporting multiple databases in the same model. This require the databases in the same machine.
+ ///
+ void ChangeDatabase(string database);
+
+ ///
+ /// Gets the specified repository for the .
+ ///
+ /// True if providing custom repositry
+ /// The type of the entity.
+ /// An instance of type inherited from interface.
+ IRepository GetRepository(bool hasCustomRepository = false) where TEntity : class;
+
+ ///
+ /// Gets the db context.
+ ///
+ ///
+ TContext GetDbContext() where TContext : DbContext;
+
+ ///
+ /// Saves all changes made in this context to the database.
+ ///
+ /// True if sayve changes ensure auto record the change history.
+ /// The number of state entries written to the database.
+ int SaveChanges(bool ensureAutoHistory = false);
+
+ ///
+ /// Asynchronously saves all changes made in this unit of work to the database.
+ ///
+ /// True if save changes ensure auto record the change history.
+ /// A that represents the asynchronous save operation. The task result contains the number of state entities written to database.
+ Task SaveChangesAsync(bool ensureAutoHistory = false);
+
+ ///
+ /// Executes the specified raw SQL command.
+ ///
+ /// The raw SQL.
+ /// The parameters.
+ /// The number of state entities written to database.
+ int ExecuteSqlCommand(string sql, params object[] parameters);
+
+ ///
+ /// Uses raw SQL queries to fetch the specified data.
+ ///
+ /// The type of the entity.
+ /// The raw SQL.
+ /// The parameters.
+ /// An that contains elements that satisfy the condition specified by raw SQL.
+ IQueryable FromSql(string sql, params object[] parameters) where TEntity : class;
+
+ ///
+ /// Uses TrakGrap Api to attach disconnected entities
+ ///
+ /// Root entity
+ /// Delegate to convert Object's State properities to Entities entry state.
+ void TrackGraph(object rootEntity, Action callback);
+ }
+}
diff --git a/Entities/Context/UnitOfWork/IUnitOfWorkOfT.cs b/Entities/Context/UnitOfWork/IUnitOfWorkOfT.cs
new file mode 100644
index 0000000..cfe08b6
--- /dev/null
+++ b/Entities/Context/UnitOfWork/IUnitOfWorkOfT.cs
@@ -0,0 +1,27 @@
+
+
+namespace SharedDATA.Api
+{
+ using Microsoft.EntityFrameworkCore;
+ using System.Threading.Tasks;
+
+ ///
+ /// Defines the interface(s) for generic unit of work.
+ ///
+ public interface IUnitOfWork : IUnitOfWork where TContext : DbContext
+ {
+ ///
+ /// Gets the db context.
+ ///
+ /// The instance of type .
+ TContext DbContext { get; }
+
+ ///
+ /// Saves all changes made in this context to the database with distributed transaction.
+ ///
+ /// True if save changes ensure auto record the change history.
+ /// An optional array.
+ /// A that represents the asynchronous save operation. The task result contains the number of state entities written to database.
+ Task SaveChangesAsync(bool ensureAutoHistory = false, params IUnitOfWork[] unitOfWorks);
+ }
+}
diff --git a/Entities/Context/UnitOfWork/Repository.cs b/Entities/Context/UnitOfWork/Repository.cs
new file mode 100644
index 0000000..06030e5
--- /dev/null
+++ b/Entities/Context/UnitOfWork/Repository.cs
@@ -0,0 +1,942 @@
+
+
+namespace SharedDATA.Api
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Linq.Expressions;
+ using System.Reflection;
+ using System.Threading;
+ using System.Threading.Tasks;
+ using Microsoft.EntityFrameworkCore;
+ using Microsoft.EntityFrameworkCore.Metadata;
+ using Microsoft.EntityFrameworkCore.Query;
+ using Microsoft.EntityFrameworkCore.ChangeTracking;
+ using SharedDATA.Context;
+
+ ///
+ /// Represents a default generic repository implements the interface.
+ ///
+ /// The type of the entity.
+ public class Repository : IRepository where TEntity : class
+ {
+ protected readonly DbContext _dbContext;
+ protected readonly DbSet _dbSet;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The database context.
+ public Repository(DbContext dbContext)
+ {
+ _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
+ _dbSet = _dbContext.Set();
+ }
+
+ ///
+ /// Changes the table name. This require the tables in the same database.
+ ///
+ ///
+ ///
+ /// This only been used for supporting multiple tables in the same model. This require the tables in the same database.
+ ///
+ public virtual void ChangeTable(string table)
+ {
+ if (_dbContext.Model.FindEntityType(typeof(TEntity)) is IConventionEntityType relational)
+ {
+ relational.SetTableName(table);
+ }
+ }
+
+ ///
+ /// Gets all entities. This method is not recommended
+ ///
+ /// The .
+ public IQueryable GetAll()
+ {
+ return _dbSet;
+ }
+
+ ///
+ /// Gets all entities. This method is not recommended
+ ///
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// true to disable changing tracking; otherwise, false. Default to true.
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// Ex: This method defaults to a read-only, no-tracking query.
+ public IQueryable GetAll(
+ Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null, bool disableTracking = true, bool ignoreQueryFilters = false)
+ {
+ IQueryable query = _dbSet;
+
+ if (disableTracking)
+ {
+ query = query.AsNoTracking();
+ }
+
+ if (include != null)
+ {
+ query = include(query);
+ }
+
+ if (predicate != null)
+ {
+ query = query.Where(predicate);
+ }
+
+ if (ignoreQueryFilters)
+ {
+ query = query.IgnoreQueryFilters();
+ }
+
+ if (orderBy != null)
+ {
+ return orderBy(query);
+ }
+ else
+ {
+ return query;
+ }
+ }
+ ///
+ /// Gets the based on a predicate, orderby delegate and page information. This method default no-tracking query.
+ ///
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// The index of page.
+ /// The size of the page.
+ /// True to disable changing tracking; otherwise, false. Default to true.
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// This method default no-tracking query.
+ public virtual IPagedList GetPagedList(Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ int pageIndex = 0,
+ int pageSize = 20,
+ bool disableTracking = true,
+ bool ignoreQueryFilters = false)
+ {
+ IQueryable query = _dbSet;
+
+ if (disableTracking)
+ {
+ query = query.AsNoTracking();
+ }
+
+ if (include != null)
+ {
+ query = include(query);
+ }
+
+ if (predicate != null)
+ {
+ query = query.Where(predicate);
+ }
+
+ if (ignoreQueryFilters)
+ {
+ query = query.IgnoreQueryFilters();
+ }
+
+ if (orderBy != null)
+ {
+ return orderBy(query).ToPagedList(pageIndex, pageSize);
+ }
+ else
+ {
+ return query.ToPagedList(pageIndex, pageSize);
+ }
+ }
+
+ ///
+ /// Gets the based on a predicate, orderby delegate and page information. This method default no-tracking query.
+ ///
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// The index of page.
+ /// The size of the page.
+ /// True to disable changing tracking; otherwise, false. Default to true.
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// This method default no-tracking query.
+ public virtual Task> GetPagedListAsync(Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ int pageIndex = 0,
+ int pageSize = 20,
+ bool disableTracking = true,
+ CancellationToken cancellationToken = default(CancellationToken),
+ bool ignoreQueryFilters = false)
+ {
+ IQueryable query = _dbSet;
+
+ if (disableTracking)
+ {
+ query = query.AsNoTracking();
+ }
+
+ if (include != null)
+ {
+ query = include(query);
+ }
+
+ if (predicate != null)
+ {
+ query = query.Where(predicate);
+ }
+
+ if (ignoreQueryFilters)
+ {
+ query = query.IgnoreQueryFilters();
+ }
+
+ if (orderBy != null)
+ {
+ return orderBy(query).ToPagedListAsync(pageIndex, pageSize, 0, cancellationToken);
+ }
+ else
+ {
+ return query.ToPagedListAsync(pageIndex, pageSize, 0, cancellationToken);
+ }
+ }
+
+ ///
+ /// Gets the based on a predicate, orderby delegate and page information. This method default no-tracking query.
+ ///
+ /// The selector for projection.
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// The index of page.
+ /// The size of the page.
+ /// True to disable changing tracking; otherwise, false. Default to true.
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// This method default no-tracking query.
+ public virtual IPagedList GetPagedList(Expression> selector,
+ Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ int pageIndex = 0,
+ int pageSize = 20,
+ bool disableTracking = true,
+ bool ignoreQueryFilters = false)
+ where TResult : class
+ {
+ IQueryable query = _dbSet;
+
+ if (disableTracking)
+ {
+ query = query.AsNoTracking();
+ }
+
+ if (include != null)
+ {
+ query = include(query);
+ }
+
+ if (predicate != null)
+ {
+ query = query.Where(predicate);
+ }
+
+ if (ignoreQueryFilters)
+ {
+ query = query.IgnoreQueryFilters();
+ }
+
+ if (orderBy != null)
+ {
+ return orderBy(query).Select(selector).ToPagedList(pageIndex, pageSize);
+ }
+ else
+ {
+ return query.Select(selector).ToPagedList(pageIndex, pageSize);
+ }
+ }
+
+ ///
+ /// Gets the based on a predicate, orderby delegate and page information. This method default no-tracking query.
+ ///
+ /// The selector for projection.
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// The index of page.
+ /// The size of the page.
+ /// True to disable changing tracking; otherwise, false. Default to true.
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// This method default no-tracking query.
+ public virtual Task> GetPagedListAsync(Expression> selector,
+ Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ int pageIndex = 0,
+ int pageSize = 20,
+ bool disableTracking = true,
+ CancellationToken cancellationToken = default(CancellationToken),
+ bool ignoreQueryFilters = false)
+ where TResult : class
+ {
+ IQueryable query = _dbSet;
+
+ if (disableTracking)
+ {
+ query = query.AsNoTracking();
+ }
+
+ if (include != null)
+ {
+ query = include(query);
+ }
+
+ if (predicate != null)
+ {
+ query = query.Where(predicate);
+ }
+
+ if (ignoreQueryFilters)
+ {
+ query = query.IgnoreQueryFilters();
+ }
+
+ if (orderBy != null)
+ {
+ return orderBy(query).Select(selector).ToPagedListAsync(pageIndex, pageSize, 0, cancellationToken);
+ }
+ else
+ {
+ return query.Select(selector).ToPagedListAsync(pageIndex, pageSize, 0, cancellationToken);
+ }
+ }
+
+ ///
+ /// Gets the first or default entity based on a predicate, orderby delegate and include delegate. This method default no-tracking query.
+ ///
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// True to disable changing tracking; otherwise, false. Default to true.
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// This method default no-tracking query.
+ public virtual TEntity GetFirstOrDefault(Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ bool disableTracking = true,
+ bool ignoreQueryFilters = false)
+ {
+ IQueryable query = _dbSet;
+
+ if (disableTracking)
+ {
+ query = query.AsNoTracking();
+ }
+
+ if (include != null)
+ {
+ query = include(query);
+ }
+
+ if (predicate != null)
+ {
+ query = query.Where(predicate);
+ }
+
+ if (ignoreQueryFilters)
+ {
+ query = query.IgnoreQueryFilters();
+ }
+
+ if (orderBy != null)
+ {
+ return orderBy(query).FirstOrDefault();
+ }
+ else
+ {
+ return query.FirstOrDefault();
+ }
+ }
+
+
+ ///
+ public virtual async Task GetFirstOrDefaultAsync(Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ bool disableTracking = true,
+ bool ignoreQueryFilters = false)
+ {
+ IQueryable query = _dbSet;
+
+ if (disableTracking)
+ {
+ query = query.AsNoTracking();
+ }
+
+ if (include != null)
+ {
+ query = include(query);
+ }
+
+ if (predicate != null)
+ {
+ query = query.Where(predicate);
+ }
+
+ if (ignoreQueryFilters)
+ {
+ query = query.IgnoreQueryFilters();
+ }
+
+ if (orderBy != null)
+ {
+ return await orderBy(query).FirstOrDefaultAsync();
+ }
+ else
+ {
+ return await query.FirstOrDefaultAsync();
+ }
+ }
+
+ ///
+ /// Gets the first or default entity based on a predicate, orderby delegate and include delegate. This method default no-tracking query.
+ ///
+ /// The selector for projection.
+ /// A function to test each element for a condition.
+ /// A function to order elements.
+ /// A function to include navigation properties
+ /// True to disable changing tracking; otherwise, false. Default to true.
+ /// Ignore query filters
+ /// An that contains elements that satisfy the condition specified by .
+ /// This method default no-tracking query.
+ public virtual TResult GetFirstOrDefault(Expression> selector,
+ Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ bool disableTracking = true,
+ bool ignoreQueryFilters = false)
+ {
+ IQueryable query = _dbSet;
+
+ if (disableTracking)
+ {
+ query = query.AsNoTracking();
+ }
+
+ if (include != null)
+ {
+ query = include(query);
+ }
+
+ if (predicate != null)
+ {
+ query = query.Where(predicate);
+ }
+
+ if (ignoreQueryFilters)
+ {
+ query = query.IgnoreQueryFilters();
+ }
+
+ if (orderBy != null)
+ {
+ return orderBy(query).Select(selector).FirstOrDefault();
+ }
+ else
+ {
+ return query.Select(selector).FirstOrDefault();
+ }
+ }
+
+ ///
+ public virtual async Task GetFirstOrDefaultAsync(Expression> selector,
+ Expression> predicate = null,
+ Func, IOrderedQueryable> orderBy = null,
+ Func, IIncludableQueryable> include = null,
+ bool disableTracking = true, bool ignoreQueryFilters = false)
+ {
+ IQueryable query = _dbSet;
+
+ if (disableTracking)
+ {
+ query = query.AsNoTracking();
+ }
+
+ if (include != null)
+ {
+ query = include(query);
+ }
+
+ if (predicate != null)
+ {
+ query = query.Where(predicate);
+ }
+
+ if (ignoreQueryFilters)
+ {
+ query = query.IgnoreQueryFilters();
+ }
+
+ if (orderBy != null)
+ {
+ return await orderBy(query).Select(selector).FirstOrDefaultAsync();
+ }
+ else
+ {
+ return await query.Select(selector).FirstOrDefaultAsync();
+ }
+ }
+
+ ///
+ /// Uses raw SQL queries to fetch the specified data.
+ ///
+ /// The raw SQL.
+ /// The parameters.
+ /// An that contains elements that satisfy the condition specified by raw SQL.
+ public virtual IQueryable FromSql(string sql, params object[] parameters) => _dbSet.FromSqlRaw(sql, parameters);
+
+ ///
+ /// Finds an entity with the given primary key values. If found, is attached to the context and returned. If no entity is found, then null is returned.
+ ///
+ /// The values of the primary key for the entity to be found.
+ /// The found entity or null.
+ public virtual TEntity Find(params object[] keyValues) => _dbSet.Find(keyValues);
+
+ ///
+ /// Finds an entity with the given primary key values. If found, is attached to the context and returned. If no entity is found, then null is returned.
+ ///
+ /// The values of the primary key for the entity to be found.
+ /// A that represents the asynchronous insert operation.
+ public virtual ValueTask FindAsync(params object[] keyValues) => _dbSet.FindAsync(keyValues);
+
+ ///
+ /// Finds an entity with the given primary key values. If found, is attached to the context and returned. If no entity is found, then null is returned.
+ ///
+ /// The values of the primary key for the entity to be found.
+ /// A to observe while waiting for the task to complete.
+ /// A that represents the asynchronous find operation. The task result contains the found entity or null.
+ public virtual ValueTask FindAsync(object[] keyValues, CancellationToken cancellationToken) => _dbSet.FindAsync(keyValues, cancellationToken);
+
+ ///
+ /// Gets the count based on a predicate.
+ ///
+ ///
+ ///
+ public virtual int Count(Expression> predicate = null)
+ {
+ if (predicate == null)
+ {
+ return _dbSet.Count();
+ }
+ else
+ {
+ return _dbSet.Count(predicate);
+ }
+ }
+
+ ///
+ /// Gets async the count based on a predicate.
+ ///
+ ///
+ ///
+ public virtual async Task CountAsync(Expression> predicate = null)
+ {
+ if (predicate == null)
+ {
+ return await _dbSet.CountAsync();
+ }
+ else
+ {
+ return await _dbSet.CountAsync(predicate);
+ }
+ }
+
+ ///
+ /// Gets the long count based on a predicate.
+ ///
+ ///
+ ///
+ public virtual long LongCount(Expression> predicate = null)
+ {
+ if (predicate == null)
+ {
+ return _dbSet.LongCount();
+ }
+ else
+ {
+ return _dbSet.LongCount(predicate);
+ }
+ }
+
+ ///
+ /// Gets async the long count based on a predicate.
+ ///
+ ///
+ ///
+ public virtual async Task LongCountAsync(Expression> predicate = null)
+ {
+ if (predicate == null)
+ {
+ return await _dbSet.LongCountAsync();
+ }
+ else
+ {
+ return await _dbSet.LongCountAsync(predicate);
+ }
+ }
+
+ ///
+ /// Gets the max based on a predicate.
+ ///
+ ///
+ /// ///
+ /// decimal
+ public virtual T Max(Expression> predicate = null, Expression> selector = null)
+ {
+ if (predicate == null)
+ return _dbSet.Max(selector);
+ else
+ return _dbSet.Where(predicate).Max(selector);
+ }
+
+ ///
+ /// Gets the async max based on a predicate.
+ ///
+ ///
+ /// ///
+ /// decimal
+ public virtual async Task MaxAsync(Expression> predicate = null, Expression