diff --git a/Entities/Contracts/AppMainStruct.cs b/Entities/Contracts/AppMainStruct.cs index 97b856a..8fa68b5 100644 --- a/Entities/Contracts/AppMainStruct.cs +++ b/Entities/Contracts/AppMainStruct.cs @@ -67,11 +67,11 @@ namespace Entities.Contracts ComputerScience, // 计算机科学 } - public enum QuestionGroupState : byte + public enum AssignmentStructType : byte { - Standalone, - Group, - Subquestion + Question, + Struct, + SubQuestion } } diff --git a/Entities/Contracts/Assignment.cs b/Entities/Contracts/Assignment.cs index 36e3742..ee605fc 100644 --- a/Entities/Contracts/Assignment.cs +++ b/Entities/Contracts/Assignment.cs @@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; +using Entities.DTO; namespace Entities.Contracts { @@ -53,7 +54,7 @@ namespace Entities.Contracts [ForeignKey(nameof(CreatorId))] public User Creator { get; set; } public ICollection AssignmentClasses { get; set; } - public AssignmentStruct ExamStruct { get; set; } + public AssignmentQuestion ExamStruct { get; set; } public ICollection AssignmentAttachments { get; set; } public ICollection Submissions { get; set; } diff --git a/Entities/Contracts/AssignmentQuestion.cs b/Entities/Contracts/AssignmentQuestion.cs index a7b836b..cbe0232 100644 --- a/Entities/Contracts/AssignmentQuestion.cs +++ b/Entities/Contracts/AssignmentQuestion.cs @@ -18,23 +18,28 @@ namespace Entities.Contracts public Guid Id { get; set; } [Column("question_id")] - public Guid QuestionId { get; set; } + public Guid? QuestionId { get; set; } - [Required] - [Column("group_id")] - [ForeignKey("AssignmentGroup")] - public Guid AssignmentStructId { get; set; } + [Column("assignment")] + [ForeignKey("Assignment")] + public Guid? AssignmentId { get; set; } + + [Column("title")] + [MaxLength(1024)] + public string? Title { get; set; } + + [Column("description")] + public Guid? QuestionContextId { get; set; } [Required] [Column("question_number")] public byte Index { get; set; } - [Column("parent_question_group_id")] public Guid? ParentAssignmentQuestionId { get; set; } [Column("group_state")] - public QuestionGroupState GroupState { get; set; } = QuestionGroupState.Standalone; + public AssignmentStructType StructType { get; set; } = AssignmentStructType.Question; [Column("created_at")] public DateTime CreatedAt { get; set; } @@ -42,13 +47,17 @@ namespace Entities.Contracts [Column("score")] public float? Score { get; set; } - [Column("deleted")] public bool IsDeleted { get; set; } - public Question Question { get; set; } - public AssignmentStruct AssignmentStruct { get; set; } + public Question? Question { get; set; } + public Assignment? Assignment { get; set; } + + + [ForeignKey(nameof(QuestionContextId))] + public QuestionContext? QuestionContext { get; set; } + public ICollection SubmissionDetails { get; set; } [ForeignKey(nameof(ParentAssignmentQuestionId))] diff --git a/Entities/Contracts/AssignmentStruct.cs b/Entities/Contracts/AssignmentStruct.cs deleted file mode 100644 index 4b61e9c..0000000 --- a/Entities/Contracts/AssignmentStruct.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Runtime.InteropServices; - -namespace Entities.Contracts -{ - [Table("assignment_group")] - public class AssignmentStruct - { - [Key] - [Column("id")] - public Guid Id { get; set; } - - [Column("assignment")] - [ForeignKey("Assignment")] - public Guid? AssignmentId { get; set; } - - [Required] - [Column("title")] - [MaxLength(65535)] - public string Title { get; set; } - - [Column("descript")] - [MaxLength(65535)] - public string Description { get; set; } - - [Column("layout")] - public Layout Layout { get; set; } - - [Column("total_points")] - public float? Score { get; set; } - - [Column("index")] - public byte Index { get; set; } - - [Column("parent_group")] - public Guid? ParentStructId { get; set; } - - [Column("deleted")] - public bool IsDeleted { get; set; } = false; - - // Navigation Properties - public Assignment? Assignment { get; set; } - public AssignmentStruct? ParentStruct { get; set;} - public ICollection ChildrenGroups { get; set; } - public ICollection AssignmentQuestions { get; set; } - - - public AssignmentStruct() - { - Id = Guid.NewGuid(); - ChildrenGroups = new HashSet(); - AssignmentQuestions = new HashSet(); - } - } -} diff --git a/Entities/Contracts/Question.cs b/Entities/Contracts/Question.cs index 16f80c9..fe115ea 100644 --- a/Entities/Contracts/Question.cs +++ b/Entities/Contracts/Question.cs @@ -24,8 +24,7 @@ namespace Entities.Contracts [MaxLength(65535)] public string? Answer { get; set; } - [Column("description")] - public Guid? DescriptionId { get; set; } + [Required] [Column("type")] @@ -68,11 +67,6 @@ namespace Entities.Contracts [ForeignKey(nameof(CreatorId))] public User Creator { get; set; } - [ForeignKey(nameof(DescriptionId))] - public QuestionContext Description { get; set; } - public Question? ParentQuestion { get; set; } - public ICollection? ChildrenQuestion { get; set; } - [ForeignKey(nameof(KeyPointId))] public KeyPoint? KeyPoint { get; set; } [ForeignKey(nameof(LessonId))] @@ -84,7 +78,6 @@ namespace Entities.Contracts { Id = Guid.NewGuid(); AssignmentQuestions = new HashSet(); - ChildrenQuestion = new HashSet(); } } diff --git a/Entities/Contracts/QuestionContext.cs b/Entities/Contracts/QuestionContext.cs index ce4e7fc..d78adba 100644 --- a/Entities/Contracts/QuestionContext.cs +++ b/Entities/Contracts/QuestionContext.cs @@ -13,13 +13,13 @@ namespace Entities.Contracts public string Description { get; set; } = string.Empty; - [InverseProperty(nameof(Question.Description))] - public ICollection Questions { get; set; } = new List(); + [InverseProperty(nameof(AssignmentQuestion.QuestionContext))] + public ICollection? Questions { get; set; } = new List(); public QuestionContext() { - Questions = new HashSet(); + Questions = new HashSet(); } } } diff --git a/Entities/DTO/AssignmentQuestionDto.cs b/Entities/DTO/AssignmentQuestionDto.cs index c4f7980..5068f76 100644 --- a/Entities/DTO/AssignmentQuestionDto.cs +++ b/Entities/DTO/AssignmentQuestionDto.cs @@ -9,17 +9,19 @@ namespace Entities.DTO { public class AssignmentQuestionDto { - public float Score { get; set; } = 0; + public Guid Id { get; set; } = Guid.Empty; + public string Title { get; set; } = string.Empty; + public QuestionContextDto? Description { get; set; } + public byte Index { get; set; } = 0; - public QuestionGroupState GroupState { get; set; } = QuestionGroupState.Standalone; - + public float Score { get; set; } = 0; + public Layout Layout { get; set; } = Layout.horizontal; + public AssignmentStructType StructType { get; set; } = AssignmentStructType.Question; public AssignmentQuestionDto? ParentAssignmentQuestion { get; set; } public ICollection ChildrenAssignmentQuestion { get; set; } = new List(); - - - public QuestionDto Question { get; set; } + public QuestionDto? Question { get; set; } } } diff --git a/Entities/DTO/ExamDto.cs b/Entities/DTO/ExamDto.cs index bda651c..537f59e 100644 --- a/Entities/DTO/ExamDto.cs +++ b/Entities/DTO/ExamDto.cs @@ -8,25 +8,6 @@ using System.Xml.Serialization; namespace Entities.DTO { - - public class AssignmentStructDto - { - public Guid Id { get; set; } = Guid.Empty; - public string Title { get; set; } = string.Empty; - public string Description { get; set; } = string.Empty; - public float Score { get; set; } = 0; - public byte Index { get; set; } = 0; - public Layout Layout { get; set; } = Layout.horizontal; - - - - - public ICollection AssignmentQuestions { get; set; } = new List(); - - public AssignmentStructDto? ParentStruct { get; set; } - public ICollection ChildrenGroups { get; set; } = new List(); - } - public class AssignmentDto { public Guid Id { get; set; } = Guid.Empty; @@ -41,7 +22,7 @@ namespace Entities.DTO public DateTime DueDate { get; set; } public Guid CreatorId { get; set; } - public AssignmentStructDto ExamStruct { get; set; } = new AssignmentStructDto(); + public AssignmentQuestionDto ExamStruct { get; set; } = new AssignmentQuestionDto(); } public class AssignmentClassDto diff --git a/Entities/DTO/QuestionDto.cs b/Entities/DTO/QuestionDto.cs index ca2d4fe..d30ab1d 100644 --- a/Entities/DTO/QuestionDto.cs +++ b/Entities/DTO/QuestionDto.cs @@ -15,8 +15,6 @@ namespace Entities.DTO public string Title { get; set; } = string.Empty; - public QuestionContextDto? Description { get; set; } - public QuestionType Type { get; set; } = QuestionType.Unknown; public string? Answer { get; set; } = string.Empty; diff --git a/TechHelper.Client/Exam/ExamPaperExtensions .cs b/TechHelper.Client/Exam/ExamPaperExtensions .cs index bea31f6..f98dbb7 100644 --- a/TechHelper.Client/Exam/ExamPaperExtensions .cs +++ b/TechHelper.Client/Exam/ExamPaperExtensions .cs @@ -26,12 +26,12 @@ namespace TechHelper.Client.Exam Enum.TryParse(examPaper.SubjectArea, out SubjectArea); dto.SubjectArea = SubjectArea; - AssignmentStructDto examStruct = new AssignmentStructDto(); + AssignmentQuestionDto examStruct = new AssignmentQuestionDto(); foreach (var qg in examPaper.QuestionGroups) { - examStruct.ChildrenGroups.Add(ParseMajorQuestionGroup(qg)); - examStruct.ChildrenGroups.Last().Index = (byte)(examStruct.ChildrenGroups.Count()); + examStruct.ChildrenAssignmentQuestion.Add(ParseMajorQuestionGroup(qg)); + examStruct.ChildrenAssignmentQuestion.Last().Index = (byte)(examStruct.ChildrenAssignmentQuestion.Count()); } dto.ExamStruct = examStruct; @@ -39,28 +39,20 @@ namespace TechHelper.Client.Exam return dto; } - private static AssignmentStructDto ParseMajorQuestionGroup(MajorQuestionGroup sqg) + private static AssignmentQuestionDto ParseMajorQuestionGroup(MajorQuestionGroup sqg) { - var examStruct = new AssignmentStructDto(); - + var examStruct = new AssignmentQuestionDto(); + examStruct.Title = sqg.Title; + examStruct.Score = sqg.Score; if (sqg.SubQuestionGroups != null) { - examStruct.Title = sqg.Title; - examStruct.Score = sqg.Score; - examStruct.ChildrenGroups = new List(); + + examStruct.ChildrenAssignmentQuestion = new List(); sqg.SubQuestionGroups?.ForEach(ssqg => { - if (string.IsNullOrEmpty(ssqg.Descript)) - { - examStruct.ChildrenGroups.Add(ParseMajorQuestionGroup(ssqg)); - examStruct.ChildrenGroups.Last().Index = (byte)(examStruct.ChildrenGroups.Count()); - } - else - { - examStruct.AssignmentQuestions.Add(ParseGroupToAssignmentQuestion(ssqg, false)); - examStruct.AssignmentQuestions.Last().Index = (byte)(examStruct.AssignmentQuestions.Count()); - } + examStruct.ChildrenAssignmentQuestion.Add(ParseMajorQuestionGroup(ssqg)); + examStruct.ChildrenAssignmentQuestion.Last().Index = (byte)(examStruct.ChildrenAssignmentQuestion.Count()); }); @@ -72,12 +64,8 @@ namespace TechHelper.Client.Exam sqg.SubQuestions?.ForEach(sq => { - if(sq.SubQuestions.Any()) - { - - } - examStruct.AssignmentQuestions.Add(ParseAssignmentQuestion(sq)); - examStruct.AssignmentQuestions.Last().Index = (byte)(examStruct.AssignmentQuestions.Count()); + examStruct.ChildrenAssignmentQuestion.Add(ParseAssignmentQuestion(sq)); + examStruct.ChildrenAssignmentQuestion.Last().Index = (byte)(examStruct.ChildrenAssignmentQuestion.Count()); }); } @@ -91,47 +79,6 @@ namespace TechHelper.Client.Exam .Where(line => !string.IsNullOrWhiteSpace(line)).ToList(); } - private static QuestionDto ParseGroupToQuestion(MajorQuestionGroup qg, bool subQ = true) - { - var dq = new QuestionDto(); - dq.Title = qg.Title + Environment.NewLine + qg.Descript; - - if (subQ) dq.GroupState = QuestionGroupState.Subquestion; - else dq.GroupState = QuestionGroupState.Group; - - qg.SubQuestions?.ForEach(ssq => - { - dq.ChildrenQuestion.Add(ParseQuestion(ssq)); - }); - - qg.SubQuestionGroups?.ForEach(sqg => - { - dq.ChildrenQuestion.Add(ParseGroupToQuestion(sqg)); - }); - - return dq; - } - - private static AssignmentQuestionDto ParseGroupToAssignmentQuestion(MajorQuestionGroup qg, bool subQ = true) - { - var aq = new AssignmentQuestionDto(); - aq.Score = qg.Score; - - qg.SubQuestions?.ForEach(ssq => - { - aq.Question.ChildrenQuestion.Add(ParseQuestion(ssq)); - aq.Question.ChildrenQuestion.Last().Index = (byte)aq.Question.ChildrenQuestion.Count; - }); - - qg.SubQuestionGroups?.ForEach(sqg => - { - aq.Question.ChildrenQuestion.Add(ParseGroupToQuestion(sqg)); - aq.Question.ChildrenQuestion.Last().Index = (byte)aq.Question.ChildrenQuestion.Count; - }); - - return aq; - } - private static AssignmentQuestionDto ParseAssignmentQuestion(PaperQuestion sq) { @@ -143,8 +90,8 @@ namespace TechHelper.Client.Exam sq.SubQuestions?.ForEach(ssq => { - aq.Question.ChildrenQuestion.Add(ParseQuestion(ssq)); - aq.Question.ChildrenQuestion.Last().Index = (byte)aq.Question.ChildrenQuestion.Count; + aq.ChildrenAssignmentQuestion.Add(ParseAssignmentQuestion(ssq)); + aq.ChildrenAssignmentQuestion.Last().Index = (byte)aq.ChildrenAssignmentQuestion.Count; }); @@ -156,14 +103,6 @@ namespace TechHelper.Client.Exam var dq = new QuestionDto(); dq.Title = sq.Stem; dq.Options = string.Join(Environment.NewLine, sq.Options.Select(opt => $"{opt.Label} {opt.Text}")); - dq.Score = sq.Score; - - - sq.SubQuestions?.ForEach(ssq => - { - dq.ChildrenQuestion.Add(ParseQuestion(ssq)); - dq.ChildrenQuestion.Last().Index = (byte)dq.ChildrenQuestion.Count; - }); return dq; } diff --git a/TechHelper.Client/Exam/ExamParse.cs b/TechHelper.Client/Exam/ExamParse.cs index 9aa9e1d..63860e9 100644 --- a/TechHelper.Client/Exam/ExamParse.cs +++ b/TechHelper.Client/Exam/ExamParse.cs @@ -6,14 +6,14 @@ using System.Text.RegularExpressions; namespace TechHelper.Client.Exam { - // --- 新增错误处理相关类 --- + public class ParseError { public ParseErrorType Type { get; } public string Message { get; } - public int? Index { get; } // 错误发生的文本索引或匹配项索引 - public string MatchedText { get; } // 如果与某个匹配项相关,记录其文本 - public Exception InnerException { get; } // 捕获到的原始异常 + public int? Index { get; } + public string MatchedText { get; } + public Exception InnerException { get; } public ParseError(ParseErrorType type, string message, int? index = null, string matchedText = null, Exception innerException = null) { diff --git a/TechHelper.Client/Pages/Exam/AssignmentQuestionEdit.razor b/TechHelper.Client/Pages/Exam/AssignmentQuestionEdit.razor new file mode 100644 index 0000000..3abc642 --- /dev/null +++ b/TechHelper.Client/Pages/Exam/AssignmentQuestionEdit.razor @@ -0,0 +1,17 @@ +@using Entities.DTO +@using TechHelper.Client.Exam + + + + @AssignmentQuestion.Id + + + + + + + +@code { + [Parameter] + public AssignmentQuestionDto AssignmentQuestion { get; set; } = new AssignmentQuestionDto(); +} diff --git a/TechHelper.Client/Pages/Exam/ExamCreate.razor b/TechHelper.Client/Pages/Exam/ExamCreate.razor index 9b14215..8b205ad 100644 --- a/TechHelper.Client/Pages/Exam/ExamCreate.razor +++ b/TechHelper.Client/Pages/Exam/ExamCreate.razor @@ -9,20 +9,32 @@ @using System.Globalization; @using TechHelper.Client.Pages.Editor + - - 配置 - - - - ParseExam - + @if (_edit) + { + + } + else + { + + + 配置 + + + + + ParseExam + + } + + - + @@ -75,11 +87,15 @@ [CascadingParameter] private Task authenticationStateTask { get; set; } + private AssignmentQuestionDto selectedAssignmentQuestion = new AssignmentQuestionDto(); + private bool _open = false; + private bool _edit = false; private void ToggleDrawer() { _open = !_open; + _edit = false; } private BlazoredTextEditor _textEditor = new BlazoredTextEditor(); private ExamPaper _parsedExam = new ExamPaper(); @@ -87,6 +103,14 @@ private ExamParserConfig _examParserConfig { get; set; } = new ExamParserConfig(); + private void HandleClickedStruct(AssignmentQuestionDto dto) + { + _open = true; + _edit = true; + selectedAssignmentQuestion = dto; + StateHasChanged(); + } + private async Task ParseExam() { diff --git a/TechHelper.Client/Pages/Exam/ExamGroupView.razor b/TechHelper.Client/Pages/Exam/ExamGroupView.razor deleted file mode 100644 index 0314daa..0000000 --- a/TechHelper.Client/Pages/Exam/ExamGroupView.razor +++ /dev/null @@ -1,36 +0,0 @@ -@using Entities.DTO -@using TechHelper.Client.Exam - - - - - - @ExamStruct.Title - @if (ExamStruct.Score > 0) - { - 总分: @ExamStruct.Score 分 - } - - - @foreach (var childStruct in ExamStruct.ChildrenGroups) - { - - } - - @foreach (var question in ExamStruct.AssignmentQuestions) - { - - } - - - -@code { - [Parameter] - public AssignmentStructDto ExamStruct { get; set; } = new AssignmentStructDto(); - - [Parameter] - public string Class { get; set; } = "my-2 pa-1"; - - [Parameter] - public int Elevation { get; set; } = 0; -} \ No newline at end of file diff --git a/TechHelper.Client/Pages/Exam/ExamStructView.razor b/TechHelper.Client/Pages/Exam/ExamStructView.razor new file mode 100644 index 0000000..3e6b123 --- /dev/null +++ b/TechHelper.Client/Pages/Exam/ExamStructView.razor @@ -0,0 +1,51 @@ +@using Entities.DTO +@using TechHelper.Client.Exam + + + + + + @ExamStruct.Title + @if (ExamStruct.Score > 0) + { + 总分: @ExamStruct.Score 分 + } + + + @if (ExamStruct.Question != null) + { + + } + + @foreach (var examStruct in ExamStruct.ChildrenAssignmentQuestion) + { + + } + + + + +@code { + [Parameter] + public AssignmentQuestionDto ExamStruct { get; set; } = new AssignmentQuestionDto(); + + [Parameter] + public EventCallback ClickedStruct { get; set; } + + [Parameter] + public string Class { get; set; } = "my-2 pa-1"; + + [Parameter] + public int Elevation { get; set; } = 0; + + + private async void HandleClick() + { + await ClickedStruct.InvokeAsync(ExamStruct); + } + + private async void HandleChildStructClick(AssignmentQuestionDto clickedChildExamStruct) + { + await ClickedStruct.InvokeAsync(clickedChildExamStruct); + } +} \ No newline at end of file diff --git a/TechHelper.Client/Pages/Exam/ExamView.razor b/TechHelper.Client/Pages/Exam/ExamView.razor index 8a25906..cce015b 100644 --- a/TechHelper.Client/Pages/Exam/ExamView.razor +++ b/TechHelper.Client/Pages/Exam/ExamView.razor @@ -8,7 +8,7 @@ @ParsedExam.Title @ParsedExam.Description - + } @@ -25,6 +25,10 @@ else [Parameter] public AssignmentDto ParsedExam { get; set; } = new AssignmentDto(); + + [Parameter] + public EventCallback ClickedStruct { get; set; } + [Parameter] public string Height { get; set; } = "100%"; [Parameter] @@ -33,4 +37,10 @@ else public string Class { get; set; } = ""; [Parameter] public string Style { get; set; } = ""; + + + private void HandleClickedStruct(AssignmentQuestionDto dto) + { + ClickedStruct.InvokeAsync(dto); + } } \ No newline at end of file diff --git a/TechHelper.Client/Pages/Exam/QuestionCard.razor b/TechHelper.Client/Pages/Exam/QuestionCard.razor index cfc3f57..47d3134 100644 --- a/TechHelper.Client/Pages/Exam/QuestionCard.razor +++ b/TechHelper.Client/Pages/Exam/QuestionCard.razor @@ -4,14 +4,14 @@ - @Question.Index @((MarkupString)Question.Title.Replace("\n", "
")) - @if (Question.Score > 0) + @Index @((MarkupString)Question.Title.Replace("\n", "
")) + @if (Score > 0) { - (@Question.Score 分) + (@Score 分) }
- @if (Question.Options != null) + @if (!string.IsNullOrEmpty(Question.Options)) {
@foreach (var option in Question.Options.ParseOptionsFromText()) @@ -22,12 +22,6 @@
} - - @foreach(var item in Question.ChildrenQuestion) - { - - - }
@code { @@ -35,7 +29,13 @@ public QuestionDto Question { get; set; } = new QuestionDto(); [Parameter] - public string Class { get; set; } + public byte Index { get; set; } = 0; + + [Parameter] + public byte Score { get; set; } = 0; + + [Parameter] + public string Class { get; set; } = string.Empty; [Parameter] public int Elevation { get; set; } diff --git a/TechHelper.Client/Pages/Exam/QuestionEdit.razor b/TechHelper.Client/Pages/Exam/QuestionEdit.razor new file mode 100644 index 0000000..838dc5e --- /dev/null +++ b/TechHelper.Client/Pages/Exam/QuestionEdit.razor @@ -0,0 +1,17 @@ +@using Entities.DTO +@using TechHelper.Client.Exam + + + + @Question.Id + + + + + + + +@code { + [Parameter] + public QuestionDto Question { get; set; } = new QuestionDto(); +} diff --git a/TechHelper.Server/Context/ApplicationContext.cs b/TechHelper.Server/Context/ApplicationContext.cs index ea3a01c..5cedc4a 100644 --- a/TechHelper.Server/Context/ApplicationContext.cs +++ b/TechHelper.Server/Context/ApplicationContext.cs @@ -13,7 +13,6 @@ namespace TechHelper.Context public DbSet AssignmentClasses { get; set; } public DbSet Assignments { get; set; } - public DbSet AssignmentGroups { get; set; } public DbSet AssignmentQuestions { get; set; } public DbSet Classes { get; set; } public DbSet ClassStudents { get; set; } @@ -21,6 +20,7 @@ namespace TechHelper.Context public DbSet Questions { get; set; } public DbSet Submissions { get; set; } public DbSet SubmissionDetails { get; set; } + public DbSet QuestionContexts { get; set; } protected override void OnModelCreating(ModelBuilder builder) { @@ -28,7 +28,6 @@ namespace TechHelper.Context builder.ApplyConfiguration(new RoleConfiguration()); builder.ApplyConfiguration(new AssignmentConfiguration()); builder.ApplyConfiguration(new AssignmentClassConfiguration()); - builder.ApplyConfiguration(new AssignmentGroupConfiguration()); builder.ApplyConfiguration(new AssignmentQuestionConfiguration()); builder.ApplyConfiguration(new ClassConfiguration()); builder.ApplyConfiguration(new ClassStudentConfiguration()); diff --git a/TechHelper.Server/Context/AutoMapperProFile.cs b/TechHelper.Server/Context/AutoMapperProFile.cs index 57ace8c..5d8a88b 100644 --- a/TechHelper.Server/Context/AutoMapperProFile.cs +++ b/TechHelper.Server/Context/AutoMapperProFile.cs @@ -50,10 +50,11 @@ namespace TechHelper.Context // ============================================================= // ENTITY -> DTO Mappings (用于读取/查询) // ============================================================= - CreateMap() - .ForMember(dest => dest.ExamStruct, opt => opt.MapFrom(src => src.ExamStruct)); + CreateMap(); + + CreateMap().ReverseMap(); + - CreateMap(); // 直接映射,因为成员现在对等了 // 新增!从实体到新的 DTO 的映射 CreateMap(); @@ -64,7 +65,6 @@ namespace TechHelper.Context // DTO -> ENTITY Mappings (用于创建/更新) - 现在变得极其简单! // ================================================================= CreateMap(); - CreateMap(); // 新增!从新的 DTO 到实体的映射 CreateMap(); diff --git a/TechHelper.Server/Context/Configuration/AssignmentGroupConfiguration.cs b/TechHelper.Server/Context/Configuration/AssignmentGroupConfiguration.cs deleted file mode 100644 index d8c7828..0000000 --- a/TechHelper.Server/Context/Configuration/AssignmentGroupConfiguration.cs +++ /dev/null @@ -1,83 +0,0 @@ -using Entities.Contracts; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Microsoft.EntityFrameworkCore; - -namespace TechHelper.Context.Configuration -{ - public class AssignmentGroupConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - // 1. 设置表名 - // 将此实体映射到数据库中名为 "assignment_detail" 的表。 - builder.ToTable("assignment_group"); - - // 2. 配置主键 - // Id 属性作为主键。 - builder.HasKey(ag => ag.Id); - - // 3. 配置列名、必需性、长度和默认值 - - // 配置 Id 属性对应的数据库列名为 "id"。 - builder.Property(ag => ag.Id) - .HasColumnName("id"); - // EF Core 默认 Guid 类型主键由应用程序生成,因此无需 ValueGeneratedOnAdd()。 - - // 配置 AssignmentId 属性对应的数据库列名为 "assignment",并设置为必需字段。 - builder.Property(ag => ag.AssignmentId) - .HasColumnName("assignment"); - - // 配置 Title 属性对应的数据库列名为 "title",设置为必需字段,并设置最大长度。 - builder.Property(ag => ag.Title) - .HasColumnName("title") - .IsRequired() - .HasMaxLength(65535); // 对应 MaxLength(65535) - - // 配置 Descript 属性对应的数据库列名为 "descript",并设置最大长度。 - builder.Property(ag => ag.Description) - .HasColumnName("descript") - .HasMaxLength(65535); // 对应 MaxLength(65535) - - // 配置 TotalPoints 属性对应的数据库列名为 "total_points"。 - // TotalPoints 是 decimal? 类型,默认就是可选的,无需 IsRequired(false)。 - builder.Property(ag => ag.Score) - .HasColumnName("total_points"); - - // 配置 Number 属性对应的数据库列名为 "number"。 - builder.Property(ag => ag.Index) - .HasColumnName("number") - .IsRequired(); // byte 默认非空,显式 IsRequired 增加可读性。 - - // 配置 ParentGroup 属性对应的数据库列名为 "sub_group"。 - // ParentGroup 是 Guid? 类型,默认就是可选的,无需 IsRequired(false)。 - builder.Property(ag => ag.ParentStructId) - .HasColumnName("parent_group") - .IsRequired(false); - - // 配置 IsDeleted 属性对应的数据库列名为 "deleted",并设置默认值为 false。 - builder.Property(ag => ag.IsDeleted) - .HasColumnName("deleted") - .HasDefaultValue(false); // 适用于软删除策略 - - // 4. 配置导航属性和外键关系 - - // 配置 AssignmentGroup 到 Assignment 的多对一关系。 - // 一个 AssignmentGroup 记录属于一个 Assignment。 - builder.HasOne(ag => ag.Assignment) // 当前 AssignmentGroup 有一个 Assignment - .WithOne(a => a.ExamStruct) // 该 Assignment 可以有多个 AssignmentGroup 记录 - .HasForeignKey(ag => ag.AssignmentId); // 通过 AssignmentId 建立外键 - - - // 配置 AssignmentGroup 到 AssignmentGroup 的自引用关系(父子关系)。 - // 一个 AssignmentGroup 可以有一个父 AssignmentGroup (SubAssignmentGroup)。 - // 假设父 AssignmentGroup 实体中有一个名为 ChildAssignmentGroups 的集合属性来表示它所包含的所有子组。 - builder.HasOne(ag => ag.ParentStruct) // 当前 AssignmentGroup 有一个父 AssignmentGroup - .WithMany(parentAg => parentAg.ChildrenGroups) // 该父 AssignmentGroup 可以有多个子 AssignmentGroup - .HasForeignKey(ag => ag.ParentStructId) // 通过 SubGroup 建立外键 - .IsRequired(false) // SubGroup 是可空的 (Guid?),所以这个关系是可选的。 - .OnDelete(DeleteBehavior.SetNull); // 当父 AssignmentGroup 被删除时,其子 AssignmentGroup 的 SubGroup 外键将被设置为 NULL。 - // 如果你希望父组被删除时子组不能脱离父组(即不允许父组被删除), - // 可以使用 DeleteBehavior.Restrict 或 DeleteBehavior.NoAction。 - } - } -} \ No newline at end of file diff --git a/TechHelper.Server/Context/Configuration/AssignmentQuestionConfiguration.cs b/TechHelper.Server/Context/Configuration/AssignmentQuestionConfiguration.cs index 93413f3..e999dc1 100644 --- a/TechHelper.Server/Context/Configuration/AssignmentQuestionConfiguration.cs +++ b/TechHelper.Server/Context/Configuration/AssignmentQuestionConfiguration.cs @@ -38,12 +38,6 @@ namespace TechHelper.Context.Configuration builder.Property(aq => aq.Score) .HasColumnName("score"); - // 配置 AssignmentGroupId 列 - // 该列在数据库中名为 "detail_id" - builder.Property(aq => aq.AssignmentStructId) - .HasColumnName("group_id") - .IsRequired(); - builder.Property(aq => aq.IsDeleted) .HasColumnName("deleted") .HasDefaultValue(false); // 适用于软删除策略 @@ -60,17 +54,11 @@ namespace TechHelper.Context.Configuration .HasForeignKey(aq => aq.QuestionId) // 外键是 AssignmentQuestion.QuestionId .OnDelete(DeleteBehavior.Cascade); // 当 Question 被删除时,相关的 AssignmentQuestion 也级联删除。 - // --- - // 配置 AssignmentQuestion 到 AssignmentGroup 的关系 (多对一) - // 一个 AssignmentQuestion 属于一个 AssignmentGroup。 - // - // 你的 `AssignmentQuestion` 类现在有了 `public AssignmentGroup AssignmentGroup { get; set; }` - // 这是一个非常好的改进,它与 `AssignmentGroupId` 外键完美匹配。 - // 假设 `AssignmentGroup` 实体中有一个名为 `AssignmentQuestions` 的 `ICollection` 集合属性。 - builder.HasOne(aq => aq.AssignmentStruct) // 当前 AssignmentQuestion 有一个 AssignmentGroup - .WithMany(ag => ag.AssignmentQuestions) // 那个 AssignmentGroup 可以有多个 AssignmentQuestion - .HasForeignKey(aq => aq.AssignmentStructId) // 外键是 AssignmentQuestion.AssignmentGroupId (列名 detail_id) - .OnDelete(DeleteBehavior.Cascade); // 当 AssignmentGroup 被删除时,相关的 AssignmentQuestion 也级联删除。 + + builder.HasOne(aq => aq.QuestionContext) + .WithMany(qc => qc.Questions) + .HasForeignKey(aq => aq.QuestionContextId) + .OnDelete(DeleteBehavior.SetNull); // --- // 配置 AssignmentQuestion 到 SubmissionDetail 的关系 (一对多) diff --git a/TechHelper.Server/Context/Configuration/QuestionConfiguration.cs b/TechHelper.Server/Context/Configuration/QuestionConfiguration.cs index f786b01..ab3df97 100644 --- a/TechHelper.Server/Context/Configuration/QuestionConfiguration.cs +++ b/TechHelper.Server/Context/Configuration/QuestionConfiguration.cs @@ -111,11 +111,6 @@ namespace TechHelper.Context.Configuration .HasForeignKey(q => q.LessonId) .OnDelete(DeleteBehavior.SetNull); - builder.HasOne(q => q.ParentQuestion) - .WithMany(pq => pq.ChildrenQuestion) - .IsRequired(false) - .HasForeignKey(q => q.ParentQuestionId) - .OnDelete(DeleteBehavior.SetNull); } } diff --git a/TechHelper.Server/Migrations/20250619070929_init.Designer.cs b/TechHelper.Server/Migrations/20250620104952_init.Designer.cs similarity index 92% rename from TechHelper.Server/Migrations/20250619070929_init.Designer.cs rename to TechHelper.Server/Migrations/20250620104952_init.Designer.cs index 6d3846f..5215334 100644 --- a/TechHelper.Server/Migrations/20250619070929_init.Designer.cs +++ b/TechHelper.Server/Migrations/20250620104952_init.Designer.cs @@ -12,7 +12,7 @@ using TechHelper.Context; namespace TechHelper.Server.Migrations { [DbContext(typeof(ApplicationContext))] - [Migration("20250619070929_init")] + [Migration("20250620104952_init")] partial class init { /// @@ -161,9 +161,9 @@ namespace TechHelper.Server.Migrations .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("AssignmentGroupId") + b.Property("AssignmentId") .HasColumnType("char(36)") - .HasColumnName("group_id"); + .HasColumnName("assignment"); b.Property("CreatedAt") .HasColumnType("datetime(6)") @@ -179,7 +179,15 @@ namespace TechHelper.Server.Migrations .HasDefaultValue(false) .HasColumnName("deleted"); - b.Property("QuestionId") + b.Property("ParentAssignmentQuestionId") + .HasColumnType("char(36)") + .HasColumnName("parent_question_group_id"); + + b.Property("QuestionContextId") + .HasColumnType("char(36)") + .HasColumnName("description"); + + b.Property("QuestionId") .HasColumnType("char(36)") .HasColumnName("question_id"); @@ -187,58 +195,13 @@ namespace TechHelper.Server.Migrations .HasColumnType("float") .HasColumnName("score"); - b.HasKey("Id"); - - b.HasIndex("AssignmentGroupId"); - - b.HasIndex("QuestionId"); - - b.ToTable("assignment_questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentStruct", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment"); - - b.Property("Description") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("descript"); - - b.Property("Index") + b.Property("StructType") .HasColumnType("tinyint unsigned") - .HasColumnName("number"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Layout") - .HasColumnType("tinyint unsigned") - .HasColumnName("layout"); - - b.Property("ParentGroupId") - .HasColumnType("char(36)") - .HasColumnName("parent_group"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("total_points"); + .HasColumnName("group_state"); b.Property("Title") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)") .HasColumnName("title"); b.HasKey("Id"); @@ -246,9 +209,13 @@ namespace TechHelper.Server.Migrations b.HasIndex("AssignmentId") .IsUnique(); - b.HasIndex("ParentGroupId"); + b.HasIndex("ParentAssignmentQuestionId"); - b.ToTable("assignment_group", (string)null); + b.HasIndex("QuestionContextId"); + + b.HasIndex("QuestionId"); + + b.ToTable("assignment_questions", (string)null); }); modelBuilder.Entity("Entities.Contracts.Class", b => @@ -408,6 +375,7 @@ namespace TechHelper.Server.Migrations b.Property("Question") .IsRequired() + .HasMaxLength(65535) .HasColumnType("longtext"); b.HasKey("Id"); @@ -445,10 +413,6 @@ namespace TechHelper.Server.Migrations .HasColumnType("tinyint unsigned") .HasColumnName("difficulty_level"); - b.Property("GroupState") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - b.Property("IsDeleted") .ValueGeneratedOnAdd() .HasColumnType("tinyint(1)") @@ -467,10 +431,6 @@ namespace TechHelper.Server.Migrations .HasColumnType("longtext") .HasColumnName("options"); - b.Property("ParentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("parent_question_group_id"); - b.Property("SubjectArea") .HasMaxLength(100) .HasColumnType("tinyint unsigned") @@ -501,14 +461,27 @@ namespace TechHelper.Server.Migrations b.HasIndex("LessonId"); - b.HasIndex("ParentQuestionId"); - b.HasIndex("Title") .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); b.ToTable("questions", (string)null); }); + modelBuilder.Entity("Entities.Contracts.QuestionContext", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("QuestionContexts"); + }); + modelBuilder.Entity("Entities.Contracts.Submission", b => { b.Property("Id") @@ -774,19 +747,19 @@ namespace TechHelper.Server.Migrations b.HasData( new { - Id = new Guid("895d8f32-714e-4a14-bd97-8fa262b83172"), + Id = new Guid("577dbfe8-7b77-4ead-9386-678f02dea5f4"), Name = "Student", NormalizedName = "STUDENT" }, new { - Id = new Guid("d182c396-c656-42da-965a-d93c17a1f74f"), + Id = new Guid("04b04eed-32b9-4eb0-b5f5-a97bb4626718"), Name = "Teacher", NormalizedName = "TEACHER" }, new { - Id = new Guid("4e65fab9-3315-4474-b92c-bdab5a617e65"), + Id = new Guid("82354e4d-902d-4dd6-9790-6ef50ba9bc11"), Name = "Administrator", NormalizedName = "ADMINISTRATOR" }); @@ -942,37 +915,31 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => { - b.HasOne("Entities.Contracts.AssignmentStruct", "AssignmentGroup") - .WithMany("AssignmentQuestions") - .HasForeignKey("AssignmentGroupId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + b.HasOne("Entities.Contracts.Assignment", "Assignment") + .WithOne("ExamStruct") + .HasForeignKey("Entities.Contracts.AssignmentQuestion", "AssignmentId"); + + b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") + .WithMany("ChildrenAssignmentQuestion") + .HasForeignKey("ParentAssignmentQuestionId"); + + b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") + .WithMany("Questions") + .HasForeignKey("QuestionContextId") + .OnDelete(DeleteBehavior.SetNull); b.HasOne("Entities.Contracts.Question", "Question") .WithMany("AssignmentQuestions") .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("AssignmentGroup"); - - b.Navigation("Question"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentStruct", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithOne("ExamStruct") - .HasForeignKey("Entities.Contracts.AssignmentStruct", "AssignmentId"); - - b.HasOne("Entities.Contracts.AssignmentStruct", "ParentGroup") - .WithMany("ChildrenGroups") - .HasForeignKey("ParentGroupId") - .OnDelete(DeleteBehavior.SetNull); + .OnDelete(DeleteBehavior.Cascade); b.Navigation("Assignment"); - b.Navigation("ParentGroup"); + b.Navigation("ParentAssignmentQuestion"); + + b.Navigation("Question"); + + b.Navigation("QuestionContext"); }); modelBuilder.Entity("Entities.Contracts.Class", b => @@ -1075,18 +1042,11 @@ namespace TechHelper.Server.Migrations .HasForeignKey("LessonId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Entities.Contracts.Question", "ParentQuestion") - .WithMany("ChildrenQuestion") - .HasForeignKey("ParentQuestionId") - .OnDelete(DeleteBehavior.SetNull); - b.Navigation("Creator"); b.Navigation("KeyPoint"); b.Navigation("Lesson"); - - b.Navigation("ParentQuestion"); }); modelBuilder.Entity("Entities.Contracts.Submission", b => @@ -1207,16 +1167,11 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => { + b.Navigation("ChildrenAssignmentQuestion"); + b.Navigation("SubmissionDetails"); }); - modelBuilder.Entity("Entities.Contracts.AssignmentStruct", b => - { - b.Navigation("AssignmentQuestions"); - - b.Navigation("ChildrenGroups"); - }); - modelBuilder.Entity("Entities.Contracts.Class", b => { b.Navigation("AssignmentClasses"); @@ -1243,8 +1198,11 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.Question", b => { b.Navigation("AssignmentQuestions"); + }); - b.Navigation("ChildrenQuestion"); + modelBuilder.Entity("Entities.Contracts.QuestionContext", b => + { + b.Navigation("Questions"); }); modelBuilder.Entity("Entities.Contracts.Submission", b => diff --git a/TechHelper.Server/Migrations/20250619070929_init.cs b/TechHelper.Server/Migrations/20250620104952_init.cs similarity index 93% rename from TechHelper.Server/Migrations/20250619070929_init.cs rename to TechHelper.Server/Migrations/20250620104952_init.cs index 58557ad..d2457d4 100644 --- a/TechHelper.Server/Migrations/20250619070929_init.cs +++ b/TechHelper.Server/Migrations/20250620104952_init.cs @@ -77,6 +77,20 @@ namespace TechHelper.Server.Migrations }) .Annotation("MySql:CharSet", "utf8mb4"); + migrationBuilder.CreateTable( + name: "QuestionContexts", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + Description = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_QuestionContexts", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + migrationBuilder.CreateTable( name: "textbook", columns: table => new @@ -327,39 +341,6 @@ namespace TechHelper.Server.Migrations }) .Annotation("MySql:CharSet", "utf8mb4"); - migrationBuilder.CreateTable( - name: "assignment_group", - columns: table => new - { - id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - assignment = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), - title = table.Column(type: "longtext", maxLength: 65535, nullable: false) - .Annotation("MySql:CharSet", "utf8mb4"), - descript = table.Column(type: "longtext", maxLength: 65535, nullable: false) - .Annotation("MySql:CharSet", "utf8mb4"), - layout = table.Column(type: "tinyint unsigned", nullable: false), - total_points = table.Column(type: "float", nullable: true), - number = table.Column(type: "tinyint unsigned", nullable: false), - parent_group = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), - deleted = table.Column(type: "tinyint(1)", nullable: false, defaultValue: false) - }, - constraints: table => - { - table.PrimaryKey("PK_assignment_group", x => x.id); - table.ForeignKey( - name: "FK_assignment_group_assignment_group_parent_group", - column: x => x.parent_group, - principalTable: "assignment_group", - principalColumn: "id", - onDelete: ReferentialAction.SetNull); - table.ForeignKey( - name: "FK_assignment_group_assignments_assignment", - column: x => x.assignment, - principalTable: "assignments", - principalColumn: "id"); - }) - .Annotation("MySql:CharSet", "utf8mb4"); - migrationBuilder.CreateTable( name: "submissions", columns: table => new @@ -507,7 +488,7 @@ namespace TechHelper.Server.Migrations columns: table => new { Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - Question = table.Column(type: "longtext", nullable: false) + Question = table.Column(type: "longtext", maxLength: 65535, nullable: false) .Annotation("MySql:CharSet", "utf8mb4"), LessonID = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") }, @@ -535,12 +516,10 @@ namespace TechHelper.Server.Migrations question_type = table.Column(type: "tinyint unsigned", maxLength: 20, nullable: false), difficulty_level = table.Column(type: "tinyint unsigned", maxLength: 10, nullable: false), subject_area = table.Column(type: "tinyint unsigned", maxLength: 100, nullable: false), - group_state = table.Column(type: "tinyint unsigned", nullable: false), options = table.Column(type: "longtext", nullable: true) .Annotation("MySql:CharSet", "utf8mb4"), key_point = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), lesson = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), - parent_question_group_id = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), created_by = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), created_at = table.Column(type: "datetime(6)", nullable: false) .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), @@ -568,12 +547,6 @@ namespace TechHelper.Server.Migrations principalTable: "lesson", principalColumn: "Id", onDelete: ReferentialAction.SetNull); - table.ForeignKey( - name: "FK_questions_questions_parent_question_group_id", - column: x => x.parent_question_group_id, - principalTable: "questions", - principalColumn: "id", - onDelete: ReferentialAction.SetNull); }) .Annotation("MySql:CharSet", "utf8mb4"); @@ -582,9 +555,14 @@ namespace TechHelper.Server.Migrations columns: table => new { id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - question_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - group_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + question_id = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + assignment = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + title = table.Column(type: "varchar(1024)", maxLength: 1024, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + description = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), question_number = table.Column(type: "tinyint unsigned", nullable: false), + parent_question_group_id = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + group_state = table.Column(type: "tinyint unsigned", nullable: false), created_at = table.Column(type: "datetime(6)", nullable: false), score = table.Column(type: "float", nullable: true), deleted = table.Column(type: "tinyint(1)", nullable: false, defaultValue: false) @@ -593,11 +571,21 @@ namespace TechHelper.Server.Migrations { table.PrimaryKey("PK_assignment_questions", x => x.id); table.ForeignKey( - name: "FK_assignment_questions_assignment_group_group_id", - column: x => x.group_id, - principalTable: "assignment_group", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); + name: "FK_assignment_questions_QuestionContexts_description", + column: x => x.description, + principalTable: "QuestionContexts", + principalColumn: "Id", + onDelete: ReferentialAction.SetNull); + table.ForeignKey( + name: "FK_assignment_questions_assignment_questions_parent_question_gr~", + column: x => x.parent_question_group_id, + principalTable: "assignment_questions", + principalColumn: "id"); + table.ForeignKey( + name: "FK_assignment_questions_assignments_assignment", + column: x => x.assignment, + principalTable: "assignments", + principalColumn: "id"); table.ForeignKey( name: "FK_assignment_questions_questions_question_id", column: x => x.question_id, @@ -655,9 +643,9 @@ namespace TechHelper.Server.Migrations columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, values: new object[,] { - { new Guid("4e65fab9-3315-4474-b92c-bdab5a617e65"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("895d8f32-714e-4a14-bd97-8fa262b83172"), null, "Student", "STUDENT" }, - { new Guid("d182c396-c656-42da-965a-d93c17a1f74f"), null, "Teacher", "TEACHER" } + { new Guid("04b04eed-32b9-4eb0-b5f5-a97bb4626718"), null, "Teacher", "TEACHER" }, + { new Guid("577dbfe8-7b77-4ead-9386-678f02dea5f4"), null, "Student", "STUDENT" }, + { new Guid("82354e4d-902d-4dd6-9790-6ef50ba9bc11"), null, "Administrator", "ADMINISTRATOR" } }); migrationBuilder.CreateIndex( @@ -708,20 +696,20 @@ namespace TechHelper.Server.Migrations column: "class_id"); migrationBuilder.CreateIndex( - name: "IX_assignment_group_assignment", - table: "assignment_group", + name: "IX_assignment_questions_assignment", + table: "assignment_questions", column: "assignment", unique: true); migrationBuilder.CreateIndex( - name: "IX_assignment_group_parent_group", - table: "assignment_group", - column: "parent_group"); + name: "IX_assignment_questions_description", + table: "assignment_questions", + column: "description"); migrationBuilder.CreateIndex( - name: "IX_assignment_questions_group_id", + name: "IX_assignment_questions_parent_question_group_id", table: "assignment_questions", - column: "group_id"); + column: "parent_question_group_id"); migrationBuilder.CreateIndex( name: "IX_assignment_questions_question_id", @@ -783,11 +771,6 @@ namespace TechHelper.Server.Migrations table: "questions", column: "lesson"); - migrationBuilder.CreateIndex( - name: "IX_questions_parent_question_group_id", - table: "questions", - column: "parent_question_group_id"); - migrationBuilder.CreateIndex( name: "IX_questions_question_text", table: "questions", @@ -874,7 +857,7 @@ namespace TechHelper.Server.Migrations name: "submissions"); migrationBuilder.DropTable( - name: "assignment_group"); + name: "QuestionContexts"); migrationBuilder.DropTable( name: "questions"); diff --git a/TechHelper.Server/Migrations/ApplicationContextModelSnapshot.cs b/TechHelper.Server/Migrations/ApplicationContextModelSnapshot.cs index b7a137f..1744502 100644 --- a/TechHelper.Server/Migrations/ApplicationContextModelSnapshot.cs +++ b/TechHelper.Server/Migrations/ApplicationContextModelSnapshot.cs @@ -158,9 +158,9 @@ namespace TechHelper.Server.Migrations .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("AssignmentGroupId") + b.Property("AssignmentId") .HasColumnType("char(36)") - .HasColumnName("group_id"); + .HasColumnName("assignment"); b.Property("CreatedAt") .HasColumnType("datetime(6)") @@ -176,7 +176,15 @@ namespace TechHelper.Server.Migrations .HasDefaultValue(false) .HasColumnName("deleted"); - b.Property("QuestionId") + b.Property("ParentAssignmentQuestionId") + .HasColumnType("char(36)") + .HasColumnName("parent_question_group_id"); + + b.Property("QuestionContextId") + .HasColumnType("char(36)") + .HasColumnName("description"); + + b.Property("QuestionId") .HasColumnType("char(36)") .HasColumnName("question_id"); @@ -184,58 +192,13 @@ namespace TechHelper.Server.Migrations .HasColumnType("float") .HasColumnName("score"); - b.HasKey("Id"); - - b.HasIndex("AssignmentGroupId"); - - b.HasIndex("QuestionId"); - - b.ToTable("assignment_questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentStruct", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment"); - - b.Property("Description") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("descript"); - - b.Property("Index") + b.Property("StructType") .HasColumnType("tinyint unsigned") - .HasColumnName("number"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Layout") - .HasColumnType("tinyint unsigned") - .HasColumnName("layout"); - - b.Property("ParentGroupId") - .HasColumnType("char(36)") - .HasColumnName("parent_group"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("total_points"); + .HasColumnName("group_state"); b.Property("Title") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)") .HasColumnName("title"); b.HasKey("Id"); @@ -243,9 +206,13 @@ namespace TechHelper.Server.Migrations b.HasIndex("AssignmentId") .IsUnique(); - b.HasIndex("ParentGroupId"); + b.HasIndex("ParentAssignmentQuestionId"); - b.ToTable("assignment_group", (string)null); + b.HasIndex("QuestionContextId"); + + b.HasIndex("QuestionId"); + + b.ToTable("assignment_questions", (string)null); }); modelBuilder.Entity("Entities.Contracts.Class", b => @@ -405,6 +372,7 @@ namespace TechHelper.Server.Migrations b.Property("Question") .IsRequired() + .HasMaxLength(65535) .HasColumnType("longtext"); b.HasKey("Id"); @@ -442,10 +410,6 @@ namespace TechHelper.Server.Migrations .HasColumnType("tinyint unsigned") .HasColumnName("difficulty_level"); - b.Property("GroupState") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - b.Property("IsDeleted") .ValueGeneratedOnAdd() .HasColumnType("tinyint(1)") @@ -464,10 +428,6 @@ namespace TechHelper.Server.Migrations .HasColumnType("longtext") .HasColumnName("options"); - b.Property("ParentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("parent_question_group_id"); - b.Property("SubjectArea") .HasMaxLength(100) .HasColumnType("tinyint unsigned") @@ -498,14 +458,27 @@ namespace TechHelper.Server.Migrations b.HasIndex("LessonId"); - b.HasIndex("ParentQuestionId"); - b.HasIndex("Title") .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); b.ToTable("questions", (string)null); }); + modelBuilder.Entity("Entities.Contracts.QuestionContext", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("QuestionContexts"); + }); + modelBuilder.Entity("Entities.Contracts.Submission", b => { b.Property("Id") @@ -771,19 +744,19 @@ namespace TechHelper.Server.Migrations b.HasData( new { - Id = new Guid("895d8f32-714e-4a14-bd97-8fa262b83172"), + Id = new Guid("577dbfe8-7b77-4ead-9386-678f02dea5f4"), Name = "Student", NormalizedName = "STUDENT" }, new { - Id = new Guid("d182c396-c656-42da-965a-d93c17a1f74f"), + Id = new Guid("04b04eed-32b9-4eb0-b5f5-a97bb4626718"), Name = "Teacher", NormalizedName = "TEACHER" }, new { - Id = new Guid("4e65fab9-3315-4474-b92c-bdab5a617e65"), + Id = new Guid("82354e4d-902d-4dd6-9790-6ef50ba9bc11"), Name = "Administrator", NormalizedName = "ADMINISTRATOR" }); @@ -939,37 +912,31 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => { - b.HasOne("Entities.Contracts.AssignmentStruct", "AssignmentGroup") - .WithMany("AssignmentQuestions") - .HasForeignKey("AssignmentGroupId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + b.HasOne("Entities.Contracts.Assignment", "Assignment") + .WithOne("ExamStruct") + .HasForeignKey("Entities.Contracts.AssignmentQuestion", "AssignmentId"); + + b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") + .WithMany("ChildrenAssignmentQuestion") + .HasForeignKey("ParentAssignmentQuestionId"); + + b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") + .WithMany("Questions") + .HasForeignKey("QuestionContextId") + .OnDelete(DeleteBehavior.SetNull); b.HasOne("Entities.Contracts.Question", "Question") .WithMany("AssignmentQuestions") .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("AssignmentGroup"); - - b.Navigation("Question"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentStruct", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithOne("ExamStruct") - .HasForeignKey("Entities.Contracts.AssignmentStruct", "AssignmentId"); - - b.HasOne("Entities.Contracts.AssignmentStruct", "ParentGroup") - .WithMany("ChildrenGroups") - .HasForeignKey("ParentGroupId") - .OnDelete(DeleteBehavior.SetNull); + .OnDelete(DeleteBehavior.Cascade); b.Navigation("Assignment"); - b.Navigation("ParentGroup"); + b.Navigation("ParentAssignmentQuestion"); + + b.Navigation("Question"); + + b.Navigation("QuestionContext"); }); modelBuilder.Entity("Entities.Contracts.Class", b => @@ -1072,18 +1039,11 @@ namespace TechHelper.Server.Migrations .HasForeignKey("LessonId") .OnDelete(DeleteBehavior.SetNull); - b.HasOne("Entities.Contracts.Question", "ParentQuestion") - .WithMany("ChildrenQuestion") - .HasForeignKey("ParentQuestionId") - .OnDelete(DeleteBehavior.SetNull); - b.Navigation("Creator"); b.Navigation("KeyPoint"); b.Navigation("Lesson"); - - b.Navigation("ParentQuestion"); }); modelBuilder.Entity("Entities.Contracts.Submission", b => @@ -1204,16 +1164,11 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => { + b.Navigation("ChildrenAssignmentQuestion"); + b.Navigation("SubmissionDetails"); }); - modelBuilder.Entity("Entities.Contracts.AssignmentStruct", b => - { - b.Navigation("AssignmentQuestions"); - - b.Navigation("ChildrenGroups"); - }); - modelBuilder.Entity("Entities.Contracts.Class", b => { b.Navigation("AssignmentClasses"); @@ -1240,8 +1195,11 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.Question", b => { b.Navigation("AssignmentQuestions"); + }); - b.Navigation("ChildrenQuestion"); + modelBuilder.Entity("Entities.Contracts.QuestionContext", b => + { + b.Navigation("Questions"); }); modelBuilder.Entity("Entities.Contracts.Submission", b => diff --git a/TechHelper.Server/Program.cs b/TechHelper.Server/Program.cs index 9a6b3fa..b181450 100644 --- a/TechHelper.Server/Program.cs +++ b/TechHelper.Server/Program.cs @@ -27,12 +27,12 @@ builder.Services.AddDbContext(options => ).AddUnitOfWork() .AddCustomRepository() .AddCustomRepository() -.AddCustomRepository() .AddCustomRepository() .AddCustomRepository() .AddCustomRepository() .AddCustomRepository() .AddCustomRepository() +.AddCustomRepository() .AddCustomRepository(); builder.Services.AddAutoMapper(typeof(AutoMapperProFile).Assembly); diff --git a/TechHelper.Server/Repositories/ExamRepository.cs b/TechHelper.Server/Repositories/ExamRepository.cs index e27d321..a948411 100644 --- a/TechHelper.Server/Repositories/ExamRepository.cs +++ b/TechHelper.Server/Repositories/ExamRepository.cs @@ -10,14 +10,12 @@ namespace TechHelper.Server.Repositories { private readonly IUnitOfWork _unitOfWork; private readonly IRepository _assignmentRepo; - private readonly IRepository _assignmentGroupRepo; private readonly IRepository _questionRepo; public ExamRepository(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; _assignmentRepo = _unitOfWork.GetRepository(); - _assignmentGroupRepo = _unitOfWork.GetRepository(); } public async Task GetFullExamByIdAsync(Guid assignmentId) @@ -27,30 +25,7 @@ namespace TechHelper.Server.Repositories } - private async Task LoadSubGroupsRecursive(AssignmentStruct group) - { - // EF Core 已经加载了下一层,我们需要确保更深层次的加载 - var groupWithChildren = await _assignmentGroupRepo.GetFirstOrDefaultAsync( - predicate: g => g.Id == group.Id, - include: source => source - .Include(g => g.ChildrenGroups.Where(cg => !cg.IsDeleted)) - .ThenInclude(cg => cg.AssignmentQuestions.Where(aq => !aq.IsDeleted)) - .ThenInclude(aq => aq.Question) - .Include(g => g.AssignmentQuestions.Where(aq => !aq.IsDeleted)) - .ThenInclude(aq => aq.Question) - ); - group.ChildrenGroups = groupWithChildren.ChildrenGroups; - group.AssignmentQuestions = groupWithChildren.AssignmentQuestions; - - if (group.ChildrenGroups != null) - { - foreach (var child in group.ChildrenGroups) - { - await LoadSubGroupsRecursive(child); - } - } - } public async Task> GetExamPreviewsByUserAsync(Guid userId) { @@ -72,11 +47,6 @@ namespace TechHelper.Server.Repositories } } - public async Task AddAsync(AssignmentStruct assignment) - { - - } - public async Task AddAsync(AssignmentQuestion assignment) { } diff --git a/TechHelper.Server/Repositories/IExamRepository.cs b/TechHelper.Server/Repositories/IExamRepository.cs index 2006d92..02e266c 100644 --- a/TechHelper.Server/Repositories/IExamRepository.cs +++ b/TechHelper.Server/Repositories/IExamRepository.cs @@ -26,7 +26,6 @@ namespace TechHelper.Server.Repositories - Task AddAsync(AssignmentStruct assignment); Task AddAsync(AssignmentQuestion assignment); diff --git a/TechHelper.Server/Repository/AssignmentGroupRepository.cs b/TechHelper.Server/Repository/QuestionContextRepository.cs similarity index 51% rename from TechHelper.Server/Repository/AssignmentGroupRepository.cs rename to TechHelper.Server/Repository/QuestionContextRepository.cs index 70785a0..12e206a 100644 --- a/TechHelper.Server/Repository/AssignmentGroupRepository.cs +++ b/TechHelper.Server/Repository/QuestionContextRepository.cs @@ -5,10 +5,13 @@ using TechHelper.Context; namespace TechHelper.Repository { - public class AssignmentGroupRepository : Repository, IRepository + public class QuestionContextRepository : Repository, IRepository { - public AssignmentGroupRepository(ApplicationContext dbContext) : base(dbContext) + public QuestionContextRepository(ApplicationContext dbContext) : base(dbContext) { + } + + } } diff --git a/TechHelper.Server/Services/ExamService.cs b/TechHelper.Server/Services/ExamService.cs index ca4365f..7cf259b 100644 --- a/TechHelper.Server/Services/ExamService.cs +++ b/TechHelper.Server/Services/ExamService.cs @@ -25,87 +25,43 @@ namespace TechHelper.Server.Services public async Task CreateExamAsync(AssignmentDto assignmentDto) { - - Assignment newAssi = _mapper.Map(assignmentDto); - - await _examRepository.AddAsync(newAssi); - - - var context = _unitOfWork.GetDbContext(); - - foreach (var entry in context.ChangeTracker.Entries()) + try { - if (entry.State == Microsoft.EntityFrameworkCore.EntityState.Added) + + Assignment newAssi = _mapper.Map(assignmentDto); + + await _examRepository.AddAsync(newAssi); + + + var context = _unitOfWork.GetDbContext(); + + foreach (var entry in context.ChangeTracker.Entries()) { - if(entry.Entity is Question newQues) + if (entry.State == Microsoft.EntityFrameworkCore.EntityState.Added) { - newQues.CreatorId = newAssi.CreatorId; + if (entry.Entity is Question newQues) + { + newQues.CreatorId = newAssi.CreatorId; + } } + } + + if (await _unitOfWork.SaveChangesAsync() > 0) + { + return ApiResponse.Success(); + } + + return ApiResponse.Error("保存失败"); } - - await _unitOfWork.SaveChangesAsync(); - - return ApiResponse.Success(); - } - - private async void ParseStruct(AssignmentStructDto assignmentStruct, Guid ParentID) - { - - var newStruct = _mapper.Map(assignmentStruct); - newStruct.ParentStructId = Guid.Empty == ParentID ? null : ParentID; - await _examRepository.AddAsync(newStruct); - - - foreach (var item in assignmentStruct.AssignmentQuestions) + catch (Exception ex) { - var newQuestion = _mapper.Map(item); - //newQuestion.ParentQuestionId = item.ParentQuestion == null ? null : item.ParentQuestion.Id; - await _examRepository.AddAsync(newQuestion); - - //await ParseAssignmentQuestion(assignmentStruct, item, newQuestion); - } - - - foreach (var item in assignmentStruct.ChildrenGroups) - { - ParseStruct(item, assignmentStruct.Id); + return ApiResponse.Error(ex.Message); } } - private async Task ParseAssignmentQuestion(AssignmentStructDto assignmentStruct, QuestionDto item, Question newQuestion) - { - AssignmentQuestion newAssignQues = new AssignmentQuestion(); - newAssignQues.QuestionId = newQuestion.Id; - newAssignQues.AssignmentStructId = assignmentStruct.Id; - newAssignQues.CreatedAt = DateTime.UtcNow; - newAssignQues.Score = item.Score; - await _examRepository.AddAsync(newAssignQues); - } - private void SetEntityIdsAndRelations(AssignmentStruct group, Guid? assignmentId, Guid creatorId) - { - group.Id = Guid.NewGuid(); - group.AssignmentId = assignmentId; - - foreach (var aq in group.AssignmentQuestions) - { - aq.Id = Guid.NewGuid(); - aq.AssignmentStructId = group.Id; - aq.Question.Id = Guid.NewGuid(); - aq.Question.CreatorId = creatorId; - aq.CreatedAt = DateTime.UtcNow; - // ... 其他默认值 - } - - foreach (var childGroup in group.ChildrenGroups) - { - // 子题组的 AssignmentId 为 null,通过 ParentGroup 关联 - SetEntityIdsAndRelations(childGroup, null, creatorId); - childGroup.ParentStructId = group.Id; - } - } public async Task GetExamByIdAsync(Guid id) { diff --git a/TechHelper.Server/Services/IAssignmentGroupService.cs b/TechHelper.Server/Services/IAssignmentGroupService.cs deleted file mode 100644 index af99867..0000000 --- a/TechHelper.Server/Services/IAssignmentGroupService.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Entities.Contracts; -using TechHelper.Services; - -namespace TechHelper.Server.Services -{ - public interface IAssignmentGroupService : IBaseService - { - } -}