AsiignmentStruct

This commit is contained in:
SpecialX
2025-06-20 18:58:11 +08:00
parent d20c051c51
commit 681c0862b6
32 changed files with 414 additions and 752 deletions

View File

@@ -67,11 +67,11 @@ namespace Entities.Contracts
ComputerScience, // 计算机科学 ComputerScience, // 计算机科学
} }
public enum QuestionGroupState : byte public enum AssignmentStructType : byte
{ {
Standalone, Question,
Group, Struct,
Subquestion SubQuestion
} }
} }

View File

@@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Entities.DTO;
namespace Entities.Contracts namespace Entities.Contracts
{ {
@@ -53,7 +54,7 @@ namespace Entities.Contracts
[ForeignKey(nameof(CreatorId))] [ForeignKey(nameof(CreatorId))]
public User Creator { get; set; } public User Creator { get; set; }
public ICollection<AssignmentClass> AssignmentClasses { get; set; } public ICollection<AssignmentClass> AssignmentClasses { get; set; }
public AssignmentStruct ExamStruct { get; set; } public AssignmentQuestion ExamStruct { get; set; }
public ICollection<AssignmentAttachment> AssignmentAttachments { get; set; } public ICollection<AssignmentAttachment> AssignmentAttachments { get; set; }
public ICollection<Submission> Submissions { get; set; } public ICollection<Submission> Submissions { get; set; }

View File

@@ -18,23 +18,28 @@ namespace Entities.Contracts
public Guid Id { get; set; } public Guid Id { get; set; }
[Column("question_id")] [Column("question_id")]
public Guid QuestionId { get; set; } public Guid? QuestionId { get; set; }
[Required] [Column("assignment")]
[Column("group_id")] [ForeignKey("Assignment")]
[ForeignKey("AssignmentGroup")] public Guid? AssignmentId { get; set; }
public Guid AssignmentStructId { get; set; }
[Column("title")]
[MaxLength(1024)]
public string? Title { get; set; }
[Column("description")]
public Guid? QuestionContextId { get; set; }
[Required] [Required]
[Column("question_number")] [Column("question_number")]
public byte Index { get; set; } public byte Index { get; set; }
[Column("parent_question_group_id")] [Column("parent_question_group_id")]
public Guid? ParentAssignmentQuestionId { get; set; } public Guid? ParentAssignmentQuestionId { get; set; }
[Column("group_state")] [Column("group_state")]
public QuestionGroupState GroupState { get; set; } = QuestionGroupState.Standalone; public AssignmentStructType StructType { get; set; } = AssignmentStructType.Question;
[Column("created_at")] [Column("created_at")]
public DateTime CreatedAt { get; set; } public DateTime CreatedAt { get; set; }
@@ -42,13 +47,17 @@ namespace Entities.Contracts
[Column("score")] [Column("score")]
public float? Score { get; set; } public float? Score { get; set; }
[Column("deleted")] [Column("deleted")]
public bool IsDeleted { get; set; } public bool IsDeleted { get; set; }
public Question Question { get; set; } public Question? Question { get; set; }
public AssignmentStruct AssignmentStruct { get; set; } public Assignment? Assignment { get; set; }
[ForeignKey(nameof(QuestionContextId))]
public QuestionContext? QuestionContext { get; set; }
public ICollection<SubmissionDetail> SubmissionDetails { get; set; } public ICollection<SubmissionDetail> SubmissionDetails { get; set; }
[ForeignKey(nameof(ParentAssignmentQuestionId))] [ForeignKey(nameof(ParentAssignmentQuestionId))]

View File

@@ -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<AssignmentStruct> ChildrenGroups { get; set; }
public ICollection<AssignmentQuestion> AssignmentQuestions { get; set; }
public AssignmentStruct()
{
Id = Guid.NewGuid();
ChildrenGroups = new HashSet<AssignmentStruct>();
AssignmentQuestions = new HashSet<AssignmentQuestion>();
}
}
}

View File

@@ -24,8 +24,7 @@ namespace Entities.Contracts
[MaxLength(65535)] [MaxLength(65535)]
public string? Answer { get; set; } public string? Answer { get; set; }
[Column("description")]
public Guid? DescriptionId { get; set; }
[Required] [Required]
[Column("type")] [Column("type")]
@@ -68,11 +67,6 @@ namespace Entities.Contracts
[ForeignKey(nameof(CreatorId))] [ForeignKey(nameof(CreatorId))]
public User Creator { get; set; } public User Creator { get; set; }
[ForeignKey(nameof(DescriptionId))]
public QuestionContext Description { get; set; }
public Question? ParentQuestion { get; set; }
public ICollection<Question>? ChildrenQuestion { get; set; }
[ForeignKey(nameof(KeyPointId))] [ForeignKey(nameof(KeyPointId))]
public KeyPoint? KeyPoint { get; set; } public KeyPoint? KeyPoint { get; set; }
[ForeignKey(nameof(LessonId))] [ForeignKey(nameof(LessonId))]
@@ -84,7 +78,6 @@ namespace Entities.Contracts
{ {
Id = Guid.NewGuid(); Id = Guid.NewGuid();
AssignmentQuestions = new HashSet<AssignmentQuestion>(); AssignmentQuestions = new HashSet<AssignmentQuestion>();
ChildrenQuestion = new HashSet<Question>();
} }
} }

View File

@@ -13,13 +13,13 @@ namespace Entities.Contracts
public string Description { get; set; } = string.Empty; public string Description { get; set; } = string.Empty;
[InverseProperty(nameof(Question.Description))] [InverseProperty(nameof(AssignmentQuestion.QuestionContext))]
public ICollection<Question> Questions { get; set; } = new List<Question>(); public ICollection<AssignmentQuestion>? Questions { get; set; } = new List<AssignmentQuestion>();
public QuestionContext() public QuestionContext()
{ {
Questions = new HashSet<Question>(); Questions = new HashSet<AssignmentQuestion>();
} }
} }
} }

View File

@@ -9,17 +9,19 @@ namespace Entities.DTO
{ {
public class AssignmentQuestionDto 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 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 AssignmentQuestionDto? ParentAssignmentQuestion { get; set; }
public ICollection<AssignmentQuestionDto> ChildrenAssignmentQuestion { get; set; } = new List<AssignmentQuestionDto>(); public ICollection<AssignmentQuestionDto> ChildrenAssignmentQuestion { get; set; } = new List<AssignmentQuestionDto>();
public QuestionDto? Question { get; set; }
public QuestionDto Question { get; set; }
} }
} }

View File

@@ -8,25 +8,6 @@ using System.Xml.Serialization;
namespace Entities.DTO 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<AssignmentQuestionDto> AssignmentQuestions { get; set; } = new List<AssignmentQuestionDto>();
public AssignmentStructDto? ParentStruct { get; set; }
public ICollection<AssignmentStructDto> ChildrenGroups { get; set; } = new List<AssignmentStructDto>();
}
public class AssignmentDto public class AssignmentDto
{ {
public Guid Id { get; set; } = Guid.Empty; public Guid Id { get; set; } = Guid.Empty;
@@ -41,7 +22,7 @@ namespace Entities.DTO
public DateTime DueDate { get; set; } public DateTime DueDate { get; set; }
public Guid CreatorId { get; set; } public Guid CreatorId { get; set; }
public AssignmentStructDto ExamStruct { get; set; } = new AssignmentStructDto(); public AssignmentQuestionDto ExamStruct { get; set; } = new AssignmentQuestionDto();
} }
public class AssignmentClassDto public class AssignmentClassDto

View File

@@ -15,8 +15,6 @@ namespace Entities.DTO
public string Title { get; set; } = string.Empty; public string Title { get; set; } = string.Empty;
public QuestionContextDto? Description { get; set; }
public QuestionType Type { get; set; } = QuestionType.Unknown; public QuestionType Type { get; set; } = QuestionType.Unknown;
public string? Answer { get; set; } = string.Empty; public string? Answer { get; set; } = string.Empty;

View File

@@ -26,12 +26,12 @@ namespace TechHelper.Client.Exam
Enum.TryParse<SubjectAreaEnum>(examPaper.SubjectArea, out SubjectArea); Enum.TryParse<SubjectAreaEnum>(examPaper.SubjectArea, out SubjectArea);
dto.SubjectArea = SubjectArea; dto.SubjectArea = SubjectArea;
AssignmentStructDto examStruct = new AssignmentStructDto(); AssignmentQuestionDto examStruct = new AssignmentQuestionDto();
foreach (var qg in examPaper.QuestionGroups) foreach (var qg in examPaper.QuestionGroups)
{ {
examStruct.ChildrenGroups.Add(ParseMajorQuestionGroup(qg)); examStruct.ChildrenAssignmentQuestion.Add(ParseMajorQuestionGroup(qg));
examStruct.ChildrenGroups.Last().Index = (byte)(examStruct.ChildrenGroups.Count()); examStruct.ChildrenAssignmentQuestion.Last().Index = (byte)(examStruct.ChildrenAssignmentQuestion.Count());
} }
dto.ExamStruct = examStruct; dto.ExamStruct = examStruct;
@@ -39,28 +39,20 @@ namespace TechHelper.Client.Exam
return dto; 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) if (sqg.SubQuestionGroups != null)
{ {
examStruct.Title = sqg.Title;
examStruct.Score = sqg.Score; examStruct.ChildrenAssignmentQuestion = new List<AssignmentQuestionDto>();
examStruct.ChildrenGroups = new List<AssignmentStructDto>();
sqg.SubQuestionGroups?.ForEach(ssqg => sqg.SubQuestionGroups?.ForEach(ssqg =>
{ {
if (string.IsNullOrEmpty(ssqg.Descript)) examStruct.ChildrenAssignmentQuestion.Add(ParseMajorQuestionGroup(ssqg));
{ examStruct.ChildrenAssignmentQuestion.Last().Index = (byte)(examStruct.ChildrenAssignmentQuestion.Count());
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());
}
}); });
@@ -72,12 +64,8 @@ namespace TechHelper.Client.Exam
sqg.SubQuestions?.ForEach(sq => sqg.SubQuestions?.ForEach(sq =>
{ {
if(sq.SubQuestions.Any()) examStruct.ChildrenAssignmentQuestion.Add(ParseAssignmentQuestion(sq));
{ examStruct.ChildrenAssignmentQuestion.Last().Index = (byte)(examStruct.ChildrenAssignmentQuestion.Count());
}
examStruct.AssignmentQuestions.Add(ParseAssignmentQuestion(sq));
examStruct.AssignmentQuestions.Last().Index = (byte)(examStruct.AssignmentQuestions.Count());
}); });
} }
@@ -91,47 +79,6 @@ namespace TechHelper.Client.Exam
.Where(line => !string.IsNullOrWhiteSpace(line)).ToList(); .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) private static AssignmentQuestionDto ParseAssignmentQuestion(PaperQuestion sq)
{ {
@@ -143,8 +90,8 @@ namespace TechHelper.Client.Exam
sq.SubQuestions?.ForEach(ssq => sq.SubQuestions?.ForEach(ssq =>
{ {
aq.Question.ChildrenQuestion.Add(ParseQuestion(ssq)); aq.ChildrenAssignmentQuestion.Add(ParseAssignmentQuestion(ssq));
aq.Question.ChildrenQuestion.Last().Index = (byte)aq.Question.ChildrenQuestion.Count; aq.ChildrenAssignmentQuestion.Last().Index = (byte)aq.ChildrenAssignmentQuestion.Count;
}); });
@@ -156,14 +103,6 @@ namespace TechHelper.Client.Exam
var dq = new QuestionDto(); var dq = new QuestionDto();
dq.Title = sq.Stem; dq.Title = sq.Stem;
dq.Options = string.Join(Environment.NewLine, sq.Options.Select(opt => $"{opt.Label} {opt.Text}")); 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; return dq;
} }

View File

@@ -6,14 +6,14 @@ using System.Text.RegularExpressions;
namespace TechHelper.Client.Exam namespace TechHelper.Client.Exam
{ {
// --- 新增错误处理相关类 ---
public class ParseError public class ParseError
{ {
public ParseErrorType Type { get; } public ParseErrorType Type { get; }
public string Message { get; } public string Message { get; }
public int? Index { get; } // 错误发生的文本索引或匹配项索引 public int? Index { get; }
public string MatchedText { get; } // 如果与某个匹配项相关,记录其文本 public string MatchedText { get; }
public Exception InnerException { get; } // 捕获到的原始异常 public Exception InnerException { get; }
public ParseError(ParseErrorType type, string message, int? index = null, string matchedText = null, Exception innerException = null) public ParseError(ParseErrorType type, string message, int? index = null, string matchedText = null, Exception innerException = null)
{ {

View File

@@ -0,0 +1,17 @@
@using Entities.DTO
@using TechHelper.Client.Exam
<MudPaper>
<MudText>@AssignmentQuestion.Id</MudText>
<MudTextField @bind-Value="AssignmentQuestion.Title" Label="Title" Variant="Variant.Outlined" Margin="Margin.Dense" AutoFocus="true" />
<MudTextField @bind-Value="AssignmentQuestion.Index" Label="Index" Variant="Variant.Outlined" Adornment="Adornment.End" AdornmentText="." Margin="Margin.Dense" AutoFocus="true" />
<MudTextField @bind-Value="AssignmentQuestion.Score" Label="Score" Variant="Variant.Outlined" Adornment="Adornment.End" AdornmentText="." Margin="Margin.Dense" AutoFocus="true" />
<QuestionEdit Question="AssignmentQuestion.Question"/>
</MudPaper>
@code {
[Parameter]
public AssignmentQuestionDto AssignmentQuestion { get; set; } = new AssignmentQuestionDto();
}

View File

@@ -9,20 +9,32 @@
@using System.Globalization; @using System.Globalization;
@using TechHelper.Client.Pages.Editor @using TechHelper.Client.Pages.Editor
<MudPaper Elevation="5" Class="d-flex overflow-hidden flex-grow-1" Style="overflow:hidden; position:relative;height:100%"> <MudPaper Elevation="5" Class="d-flex overflow-hidden flex-grow-1" Style="overflow:hidden; position:relative;height:100%">
<MudDrawerContainer Class="mud-height-full flex-grow-1" Style="height:100%"> <MudDrawerContainer Class="mud-height-full flex-grow-1" Style="height:100%">
<MudDrawer @bind-Open="@_open" Elevation="0" Variant="@DrawerVariant.Persistent" Color="Color.Primary" Anchor="Anchor.End" OverlayAutoClose="true"> <MudDrawer @bind-Open="@_open" Elevation="0" Variant="@DrawerVariant.Persistent" Color="Color.Primary" Anchor="Anchor.End" OverlayAutoClose="true">
<MudDrawerHeader>
<MudText Typo="Typo.h6"> 配置 </MudText>
</MudDrawerHeader>
<MudStack Class="overflow-auto"> @if (_edit)
<ParseRoleConfig /> {
<MudButton Color="Color.Success"> ParseExam </MudButton> <AssignmentQuestionEdit AssignmentQuestion="selectedAssignmentQuestion" />
</MudStack> }
else
{
<MudDrawerHeader>
<MudText Typo="Typo.h6"> 配置 </MudText>
</MudDrawerHeader>
<MudStack Class="overflow-auto">
<ParseRoleConfig />
<MudButton Color="Color.Success"> ParseExam </MudButton>
</MudStack>
}
</MudDrawer> </MudDrawer>
<MudStack Row="true" Class="flex-grow-1" Style="height:100%"> <MudStack Row="true" Class="flex-grow-1" Style="height:100%">
<ExamView Class="overflow-auto" ParsedExam="ExamContent"></ExamView> <ExamView Class="overflow-auto" ClickedStruct="HandleClickedStruct" ParsedExam="ExamContent"></ExamView>
<MudPaper Class="ma-2"> <MudPaper Class="ma-2">
<MudPaper Elevation="0" Style="height:calc(100% - 80px)"> <MudPaper Elevation="0" Style="height:calc(100% - 80px)">
@@ -75,11 +87,15 @@
[CascadingParameter] [CascadingParameter]
private Task<AuthenticationState> authenticationStateTask { get; set; } private Task<AuthenticationState> authenticationStateTask { get; set; }
private AssignmentQuestionDto selectedAssignmentQuestion = new AssignmentQuestionDto();
private bool _open = false; private bool _open = false;
private bool _edit = false;
private void ToggleDrawer() private void ToggleDrawer()
{ {
_open = !_open; _open = !_open;
_edit = false;
} }
private BlazoredTextEditor _textEditor = new BlazoredTextEditor(); private BlazoredTextEditor _textEditor = new BlazoredTextEditor();
private ExamPaper _parsedExam = new ExamPaper(); private ExamPaper _parsedExam = new ExamPaper();
@@ -87,6 +103,14 @@
private ExamParserConfig _examParserConfig { get; set; } = new ExamParserConfig(); private ExamParserConfig _examParserConfig { get; set; } = new ExamParserConfig();
private void HandleClickedStruct(AssignmentQuestionDto dto)
{
_open = true;
_edit = true;
selectedAssignmentQuestion = dto;
StateHasChanged();
}
private async Task ParseExam() private async Task ParseExam()
{ {

View File

@@ -1,36 +0,0 @@
@using Entities.DTO
@using TechHelper.Client.Exam
<MudPaper Elevation=@Elevation Class=@Class>
<MudStack Row="true">
<MudText Typo="Typo.h6">@ExamStruct.Title</MudText>
@if (ExamStruct.Score > 0)
{
<MudText Typo="Typo.body2"><b>总分:</b> @ExamStruct.Score 分</MudText>
}
</MudStack>
@foreach (var childStruct in ExamStruct.ChildrenGroups)
{
<ExamGroupView ExamStruct="childStruct"/>
}
@foreach (var question in ExamStruct.AssignmentQuestions)
{
<QuestionCard Question="question.Question" Elevation=@Elevation Class="my-2 pa-1" />
}
</MudPaper>
@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;
}

View File

@@ -0,0 +1,51 @@
@using Entities.DTO
@using TechHelper.Client.Exam
<MudPaper @onclick:stopPropagation>
<MudPaper Elevation=@Elevation Class=@Class @onclick="HandleClick">
<MudStack Row="true">
<MudText Typo="Typo.h6">@ExamStruct.Title</MudText>
@if (ExamStruct.Score > 0)
{
<MudText Typo="Typo.body2"><b>总分:</b> @ExamStruct.Score 分</MudText>
}
</MudStack>
@if (ExamStruct.Question != null)
{
<QuestionCard Question="ExamStruct.Question" Index="ExamStruct.Index" Elevation=@Elevation Class="my-2 pa-1" />
}
@foreach (var examStruct in ExamStruct.ChildrenAssignmentQuestion)
{
<ExamStructView ExamStruct="examStruct" ClickedStruct="HandleChildStructClick" Elevation=@Elevation Class="my-2 pa-1" />
}
</MudPaper>
</MudPaper>
@code {
[Parameter]
public AssignmentQuestionDto ExamStruct { get; set; } = new AssignmentQuestionDto();
[Parameter]
public EventCallback<AssignmentQuestionDto> 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);
}
}

View File

@@ -8,7 +8,7 @@
<MudText Class="d-flex justify-content-center" Typo="Typo.h6"> @ParsedExam.Title </MudText> <MudText Class="d-flex justify-content-center" Typo="Typo.h6"> @ParsedExam.Title </MudText>
<MudText Typo="Typo.body1"> @ParsedExam.Description </MudText> <MudText Typo="Typo.body1"> @ParsedExam.Description </MudText>
<ExamGroupView ExamStruct="@ParsedExam.ExamStruct" Elevation="1" Class="ma-0 pa-2" /> <ExamStructView ExamStruct="@ParsedExam.ExamStruct" Elevation="1" ClickedStruct="HandleClickedStruct" Class="ma-0 pa-2" />
</MudPaper> </MudPaper>
} }
@@ -25,6 +25,10 @@ else
[Parameter] [Parameter]
public AssignmentDto ParsedExam { get; set; } = new AssignmentDto(); public AssignmentDto ParsedExam { get; set; } = new AssignmentDto();
[Parameter]
public EventCallback<AssignmentQuestionDto> ClickedStruct { get; set; }
[Parameter] [Parameter]
public string Height { get; set; } = "100%"; public string Height { get; set; } = "100%";
[Parameter] [Parameter]
@@ -33,4 +37,10 @@ else
public string Class { get; set; } = ""; public string Class { get; set; } = "";
[Parameter] [Parameter]
public string Style { get; set; } = ""; public string Style { get; set; } = "";
private void HandleClickedStruct(AssignmentQuestionDto dto)
{
ClickedStruct.InvokeAsync(dto);
}
} }

View File

@@ -4,14 +4,14 @@
<MudPaper Class=@Class Elevation=@Elevation Outlined="false"> <MudPaper Class=@Class Elevation=@Elevation Outlined="false">
<MudText Typo="Typo.subtitle1"> <MudText Typo="Typo.subtitle1">
<b>@Question.Index</b> @((MarkupString)Question.Title.Replace("\n", "<br />")) <b>@Index</b> @((MarkupString)Question.Title.Replace("\n", "<br />"))
@if (Question.Score > 0) @if (Score > 0)
{ {
<MudText Typo="Typo.body2" Class="d-inline ml-2">(@Question.Score 分)</MudText> <MudText Typo="Typo.body2" Class="d-inline ml-2">(@Score 分)</MudText>
} }
</MudText> </MudText>
@if (Question.Options != null) @if (!string.IsNullOrEmpty(Question.Options))
{ {
<div class="mt-2"> <div class="mt-2">
@foreach (var option in Question.Options.ParseOptionsFromText()) @foreach (var option in Question.Options.ParseOptionsFromText())
@@ -22,12 +22,6 @@
</div> </div>
} }
@foreach(var item in Question.ChildrenQuestion)
{
<QuestionCard Question="item"/>
}
</MudPaper> </MudPaper>
@code { @code {
@@ -35,7 +29,13 @@
public QuestionDto Question { get; set; } = new QuestionDto(); public QuestionDto Question { get; set; } = new QuestionDto();
[Parameter] [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] [Parameter]
public int Elevation { get; set; } public int Elevation { get; set; }

View File

@@ -0,0 +1,17 @@
@using Entities.DTO
@using TechHelper.Client.Exam
<MudPaper>
<MudText>@Question.Id</MudText>
<MudTextField @bind-Value="Question.Title" Label="Title" Variant="Variant.Outlined" Margin="Margin.Dense" AutoGrow="true" />
<MudTextField @bind-Value="Question.Answer" Label="Answer" Variant="Variant.Outlined" Adornment="Adornment.End" AdornmentText="." Margin="Margin.Dense" AutoGrow="true" />
<MudTextField @bind-Value="Question.Options" Label="Options" Variant="Variant.Outlined" Adornment="Adornment.End" AdornmentText="." Margin="Margin.Dense" AutoGrow="true" />
</MudPaper>
@code {
[Parameter]
public QuestionDto Question { get; set; } = new QuestionDto();
}

View File

@@ -13,7 +13,6 @@ namespace TechHelper.Context
public DbSet<AssignmentClass> AssignmentClasses { get; set; } public DbSet<AssignmentClass> AssignmentClasses { get; set; }
public DbSet<Assignment> Assignments { get; set; } public DbSet<Assignment> Assignments { get; set; }
public DbSet<AssignmentQuestion> AssignmentGroups { get; set; }
public DbSet<AssignmentQuestion> AssignmentQuestions { get; set; } public DbSet<AssignmentQuestion> AssignmentQuestions { get; set; }
public DbSet<Class> Classes { get; set; } public DbSet<Class> Classes { get; set; }
public DbSet<ClassTeacher> ClassStudents { get; set; } public DbSet<ClassTeacher> ClassStudents { get; set; }
@@ -21,6 +20,7 @@ namespace TechHelper.Context
public DbSet<Question> Questions { get; set; } public DbSet<Question> Questions { get; set; }
public DbSet<Submission> Submissions { get; set; } public DbSet<Submission> Submissions { get; set; }
public DbSet<SubmissionDetail> SubmissionDetails { get; set; } public DbSet<SubmissionDetail> SubmissionDetails { get; set; }
public DbSet<QuestionContext> QuestionContexts { get; set; }
protected override void OnModelCreating(ModelBuilder builder) protected override void OnModelCreating(ModelBuilder builder)
{ {
@@ -28,7 +28,6 @@ namespace TechHelper.Context
builder.ApplyConfiguration(new RoleConfiguration()); builder.ApplyConfiguration(new RoleConfiguration());
builder.ApplyConfiguration(new AssignmentConfiguration()); builder.ApplyConfiguration(new AssignmentConfiguration());
builder.ApplyConfiguration(new AssignmentClassConfiguration()); builder.ApplyConfiguration(new AssignmentClassConfiguration());
builder.ApplyConfiguration(new AssignmentGroupConfiguration());
builder.ApplyConfiguration(new AssignmentQuestionConfiguration()); builder.ApplyConfiguration(new AssignmentQuestionConfiguration());
builder.ApplyConfiguration(new ClassConfiguration()); builder.ApplyConfiguration(new ClassConfiguration());
builder.ApplyConfiguration(new ClassStudentConfiguration()); builder.ApplyConfiguration(new ClassStudentConfiguration());

View File

@@ -50,10 +50,11 @@ namespace TechHelper.Context
// ============================================================= // =============================================================
// ENTITY -> DTO Mappings (用于读取/查询) // ENTITY -> DTO Mappings (用于读取/查询)
// ============================================================= // =============================================================
CreateMap<Assignment, AssignmentDto>() CreateMap<Assignment, AssignmentDto>();
.ForMember(dest => dest.ExamStruct, opt => opt.MapFrom(src => src.ExamStruct));
CreateMap<QuestionContext, QuestionContextDto>().ReverseMap();
CreateMap<AssignmentStruct, AssignmentStructDto>(); // 直接映射,因为成员现在对等了
// 新增!从实体到新的 DTO 的映射 // 新增!从实体到新的 DTO 的映射
CreateMap<AssignmentQuestion, AssignmentQuestionDto>(); CreateMap<AssignmentQuestion, AssignmentQuestionDto>();
@@ -64,7 +65,6 @@ namespace TechHelper.Context
// DTO -> ENTITY Mappings (用于创建/更新) - 现在变得极其简单! // DTO -> ENTITY Mappings (用于创建/更新) - 现在变得极其简单!
// ================================================================= // =================================================================
CreateMap<AssignmentDto, Assignment>(); CreateMap<AssignmentDto, Assignment>();
CreateMap<AssignmentStructDto, AssignmentStruct>();
// 新增!从新的 DTO 到实体的映射 // 新增!从新的 DTO 到实体的映射
CreateMap<AssignmentQuestionDto, AssignmentQuestion>(); CreateMap<AssignmentQuestionDto, AssignmentQuestion>();

View File

@@ -1,83 +0,0 @@
using Entities.Contracts;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore;
namespace TechHelper.Context.Configuration
{
public class AssignmentGroupConfiguration : IEntityTypeConfiguration<AssignmentStruct>
{
public void Configure(EntityTypeBuilder<AssignmentStruct> 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<AssignmentStruct>(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。
}
}
}

View File

@@ -38,12 +38,6 @@ namespace TechHelper.Context.Configuration
builder.Property(aq => aq.Score) builder.Property(aq => aq.Score)
.HasColumnName("score"); .HasColumnName("score");
// 配置 AssignmentGroupId 列
// 该列在数据库中名为 "detail_id"
builder.Property(aq => aq.AssignmentStructId)
.HasColumnName("group_id")
.IsRequired();
builder.Property(aq => aq.IsDeleted) builder.Property(aq => aq.IsDeleted)
.HasColumnName("deleted") .HasColumnName("deleted")
.HasDefaultValue(false); // 适用于软删除策略 .HasDefaultValue(false); // 适用于软删除策略
@@ -60,17 +54,11 @@ namespace TechHelper.Context.Configuration
.HasForeignKey(aq => aq.QuestionId) // 外键是 AssignmentQuestion.QuestionId .HasForeignKey(aq => aq.QuestionId) // 外键是 AssignmentQuestion.QuestionId
.OnDelete(DeleteBehavior.Cascade); // 当 Question 被删除时,相关的 AssignmentQuestion 也级联删除。 .OnDelete(DeleteBehavior.Cascade); // 当 Question 被删除时,相关的 AssignmentQuestion 也级联删除。
// ---
// 配置 AssignmentQuestion 到 AssignmentGroup 的关系 (多对一) builder.HasOne(aq => aq.QuestionContext)
// 一个 AssignmentQuestion 属于一个 AssignmentGroup。 .WithMany(qc => qc.Questions)
// .HasForeignKey(aq => aq.QuestionContextId)
// 你的 `AssignmentQuestion` 类现在有了 `public AssignmentGroup AssignmentGroup { get; set; }` .OnDelete(DeleteBehavior.SetNull);
// 这是一个非常好的改进,它与 `AssignmentGroupId` 外键完美匹配。
// 假设 `AssignmentGroup` 实体中有一个名为 `AssignmentQuestions` 的 `ICollection<AssignmentQuestion>` 集合属性。
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 也级联删除。
// --- // ---
// 配置 AssignmentQuestion 到 SubmissionDetail 的关系 (一对多) // 配置 AssignmentQuestion 到 SubmissionDetail 的关系 (一对多)

View File

@@ -111,11 +111,6 @@ namespace TechHelper.Context.Configuration
.HasForeignKey(q => q.LessonId) .HasForeignKey(q => q.LessonId)
.OnDelete(DeleteBehavior.SetNull); .OnDelete(DeleteBehavior.SetNull);
builder.HasOne(q => q.ParentQuestion)
.WithMany(pq => pq.ChildrenQuestion)
.IsRequired(false)
.HasForeignKey(q => q.ParentQuestionId)
.OnDelete(DeleteBehavior.SetNull);
} }
} }

View File

@@ -12,7 +12,7 @@ using TechHelper.Context;
namespace TechHelper.Server.Migrations namespace TechHelper.Server.Migrations
{ {
[DbContext(typeof(ApplicationContext))] [DbContext(typeof(ApplicationContext))]
[Migration("20250619070929_init")] [Migration("20250620104952_init")]
partial class init partial class init
{ {
/// <inheritdoc /> /// <inheritdoc />
@@ -161,9 +161,9 @@ namespace TechHelper.Server.Migrations
.HasColumnType("char(36)") .HasColumnType("char(36)")
.HasColumnName("id"); .HasColumnName("id");
b.Property<Guid>("AssignmentGroupId") b.Property<Guid?>("AssignmentId")
.HasColumnType("char(36)") .HasColumnType("char(36)")
.HasColumnName("group_id"); .HasColumnName("assignment");
b.Property<DateTime>("CreatedAt") b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)") .HasColumnType("datetime(6)")
@@ -179,7 +179,15 @@ namespace TechHelper.Server.Migrations
.HasDefaultValue(false) .HasDefaultValue(false)
.HasColumnName("deleted"); .HasColumnName("deleted");
b.Property<Guid>("QuestionId") b.Property<Guid?>("ParentAssignmentQuestionId")
.HasColumnType("char(36)")
.HasColumnName("parent_question_group_id");
b.Property<Guid?>("QuestionContextId")
.HasColumnType("char(36)")
.HasColumnName("description");
b.Property<Guid?>("QuestionId")
.HasColumnType("char(36)") .HasColumnType("char(36)")
.HasColumnName("question_id"); .HasColumnName("question_id");
@@ -187,58 +195,13 @@ namespace TechHelper.Server.Migrations
.HasColumnType("float") .HasColumnType("float")
.HasColumnName("score"); .HasColumnName("score");
b.HasKey("Id"); b.Property<byte>("StructType")
b.HasIndex("AssignmentGroupId");
b.HasIndex("QuestionId");
b.ToTable("assignment_questions", (string)null);
});
modelBuilder.Entity("Entities.Contracts.AssignmentStruct", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)")
.HasColumnName("id");
b.Property<Guid?>("AssignmentId")
.HasColumnType("char(36)")
.HasColumnName("assignment");
b.Property<string>("Description")
.IsRequired()
.HasMaxLength(65535)
.HasColumnType("longtext")
.HasColumnName("descript");
b.Property<byte>("Index")
.HasColumnType("tinyint unsigned") .HasColumnType("tinyint unsigned")
.HasColumnName("number"); .HasColumnName("group_state");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("tinyint(1)")
.HasDefaultValue(false)
.HasColumnName("deleted");
b.Property<byte>("Layout")
.HasColumnType("tinyint unsigned")
.HasColumnName("layout");
b.Property<Guid?>("ParentGroupId")
.HasColumnType("char(36)")
.HasColumnName("parent_group");
b.Property<float?>("Score")
.HasColumnType("float")
.HasColumnName("total_points");
b.Property<string>("Title") b.Property<string>("Title")
.IsRequired() .HasMaxLength(1024)
.HasMaxLength(65535) .HasColumnType("varchar(1024)")
.HasColumnType("longtext")
.HasColumnName("title"); .HasColumnName("title");
b.HasKey("Id"); b.HasKey("Id");
@@ -246,9 +209,13 @@ namespace TechHelper.Server.Migrations
b.HasIndex("AssignmentId") b.HasIndex("AssignmentId")
.IsUnique(); .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 => modelBuilder.Entity("Entities.Contracts.Class", b =>
@@ -408,6 +375,7 @@ namespace TechHelper.Server.Migrations
b.Property<string>("Question") b.Property<string>("Question")
.IsRequired() .IsRequired()
.HasMaxLength(65535)
.HasColumnType("longtext"); .HasColumnType("longtext");
b.HasKey("Id"); b.HasKey("Id");
@@ -445,10 +413,6 @@ namespace TechHelper.Server.Migrations
.HasColumnType("tinyint unsigned") .HasColumnType("tinyint unsigned")
.HasColumnName("difficulty_level"); .HasColumnName("difficulty_level");
b.Property<byte>("GroupState")
.HasColumnType("tinyint unsigned")
.HasColumnName("group_state");
b.Property<bool>("IsDeleted") b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("tinyint(1)") .HasColumnType("tinyint(1)")
@@ -467,10 +431,6 @@ namespace TechHelper.Server.Migrations
.HasColumnType("longtext") .HasColumnType("longtext")
.HasColumnName("options"); .HasColumnName("options");
b.Property<Guid?>("ParentQuestionId")
.HasColumnType("char(36)")
.HasColumnName("parent_question_group_id");
b.Property<byte>("SubjectArea") b.Property<byte>("SubjectArea")
.HasMaxLength(100) .HasMaxLength(100)
.HasColumnType("tinyint unsigned") .HasColumnType("tinyint unsigned")
@@ -501,14 +461,27 @@ namespace TechHelper.Server.Migrations
b.HasIndex("LessonId"); b.HasIndex("LessonId");
b.HasIndex("ParentQuestionId");
b.HasIndex("Title") b.HasIndex("Title")
.HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 });
b.ToTable("questions", (string)null); b.ToTable("questions", (string)null);
}); });
modelBuilder.Entity("Entities.Contracts.QuestionContext", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("QuestionContexts");
});
modelBuilder.Entity("Entities.Contracts.Submission", b => modelBuilder.Entity("Entities.Contracts.Submission", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@@ -774,19 +747,19 @@ namespace TechHelper.Server.Migrations
b.HasData( b.HasData(
new new
{ {
Id = new Guid("895d8f32-714e-4a14-bd97-8fa262b83172"), Id = new Guid("577dbfe8-7b77-4ead-9386-678f02dea5f4"),
Name = "Student", Name = "Student",
NormalizedName = "STUDENT" NormalizedName = "STUDENT"
}, },
new new
{ {
Id = new Guid("d182c396-c656-42da-965a-d93c17a1f74f"), Id = new Guid("04b04eed-32b9-4eb0-b5f5-a97bb4626718"),
Name = "Teacher", Name = "Teacher",
NormalizedName = "TEACHER" NormalizedName = "TEACHER"
}, },
new new
{ {
Id = new Guid("4e65fab9-3315-4474-b92c-bdab5a617e65"), Id = new Guid("82354e4d-902d-4dd6-9790-6ef50ba9bc11"),
Name = "Administrator", Name = "Administrator",
NormalizedName = "ADMINISTRATOR" NormalizedName = "ADMINISTRATOR"
}); });
@@ -942,37 +915,31 @@ namespace TechHelper.Server.Migrations
modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b =>
{ {
b.HasOne("Entities.Contracts.AssignmentStruct", "AssignmentGroup") b.HasOne("Entities.Contracts.Assignment", "Assignment")
.WithMany("AssignmentQuestions") .WithOne("ExamStruct")
.HasForeignKey("AssignmentGroupId") .HasForeignKey("Entities.Contracts.AssignmentQuestion", "AssignmentId");
.OnDelete(DeleteBehavior.Cascade)
.IsRequired(); 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") b.HasOne("Entities.Contracts.Question", "Question")
.WithMany("AssignmentQuestions") .WithMany("AssignmentQuestions")
.HasForeignKey("QuestionId") .HasForeignKey("QuestionId")
.OnDelete(DeleteBehavior.Cascade) .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);
b.Navigation("Assignment"); b.Navigation("Assignment");
b.Navigation("ParentGroup"); b.Navigation("ParentAssignmentQuestion");
b.Navigation("Question");
b.Navigation("QuestionContext");
}); });
modelBuilder.Entity("Entities.Contracts.Class", b => modelBuilder.Entity("Entities.Contracts.Class", b =>
@@ -1075,18 +1042,11 @@ namespace TechHelper.Server.Migrations
.HasForeignKey("LessonId") .HasForeignKey("LessonId")
.OnDelete(DeleteBehavior.SetNull); .OnDelete(DeleteBehavior.SetNull);
b.HasOne("Entities.Contracts.Question", "ParentQuestion")
.WithMany("ChildrenQuestion")
.HasForeignKey("ParentQuestionId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Creator"); b.Navigation("Creator");
b.Navigation("KeyPoint"); b.Navigation("KeyPoint");
b.Navigation("Lesson"); b.Navigation("Lesson");
b.Navigation("ParentQuestion");
}); });
modelBuilder.Entity("Entities.Contracts.Submission", b => modelBuilder.Entity("Entities.Contracts.Submission", b =>
@@ -1207,16 +1167,11 @@ namespace TechHelper.Server.Migrations
modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b =>
{ {
b.Navigation("ChildrenAssignmentQuestion");
b.Navigation("SubmissionDetails"); b.Navigation("SubmissionDetails");
}); });
modelBuilder.Entity("Entities.Contracts.AssignmentStruct", b =>
{
b.Navigation("AssignmentQuestions");
b.Navigation("ChildrenGroups");
});
modelBuilder.Entity("Entities.Contracts.Class", b => modelBuilder.Entity("Entities.Contracts.Class", b =>
{ {
b.Navigation("AssignmentClasses"); b.Navigation("AssignmentClasses");
@@ -1243,8 +1198,11 @@ namespace TechHelper.Server.Migrations
modelBuilder.Entity("Entities.Contracts.Question", b => modelBuilder.Entity("Entities.Contracts.Question", b =>
{ {
b.Navigation("AssignmentQuestions"); b.Navigation("AssignmentQuestions");
});
b.Navigation("ChildrenQuestion"); modelBuilder.Entity("Entities.Contracts.QuestionContext", b =>
{
b.Navigation("Questions");
}); });
modelBuilder.Entity("Entities.Contracts.Submission", b => modelBuilder.Entity("Entities.Contracts.Submission", b =>

View File

@@ -77,6 +77,20 @@ namespace TechHelper.Server.Migrations
}) })
.Annotation("MySql:CharSet", "utf8mb4"); .Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "QuestionContexts",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Description = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_QuestionContexts", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "textbook", name: "textbook",
columns: table => new columns: table => new
@@ -327,39 +341,6 @@ namespace TechHelper.Server.Migrations
}) })
.Annotation("MySql:CharSet", "utf8mb4"); .Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "assignment_group",
columns: table => new
{
id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
assignment = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
title = table.Column<string>(type: "longtext", maxLength: 65535, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
descript = table.Column<string>(type: "longtext", maxLength: 65535, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
layout = table.Column<byte>(type: "tinyint unsigned", nullable: false),
total_points = table.Column<float>(type: "float", nullable: true),
number = table.Column<byte>(type: "tinyint unsigned", nullable: false),
parent_group = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
deleted = table.Column<bool>(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( migrationBuilder.CreateTable(
name: "submissions", name: "submissions",
columns: table => new columns: table => new
@@ -507,7 +488,7 @@ namespace TechHelper.Server.Migrations
columns: table => new columns: table => new
{ {
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Question = table.Column<string>(type: "longtext", nullable: false) Question = table.Column<string>(type: "longtext", maxLength: 65535, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"), .Annotation("MySql:CharSet", "utf8mb4"),
LessonID = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci") LessonID = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci")
}, },
@@ -535,12 +516,10 @@ namespace TechHelper.Server.Migrations
question_type = table.Column<byte>(type: "tinyint unsigned", maxLength: 20, nullable: false), question_type = table.Column<byte>(type: "tinyint unsigned", maxLength: 20, nullable: false),
difficulty_level = table.Column<byte>(type: "tinyint unsigned", maxLength: 10, nullable: false), difficulty_level = table.Column<byte>(type: "tinyint unsigned", maxLength: 10, nullable: false),
subject_area = table.Column<byte>(type: "tinyint unsigned", maxLength: 100, nullable: false), subject_area = table.Column<byte>(type: "tinyint unsigned", maxLength: 100, nullable: false),
group_state = table.Column<byte>(type: "tinyint unsigned", nullable: false),
options = table.Column<string>(type: "longtext", nullable: true) options = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"), .Annotation("MySql:CharSet", "utf8mb4"),
key_point = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), key_point = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
lesson = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), lesson = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
parent_question_group_id = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
created_by = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), created_by = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
created_at = table.Column<DateTime>(type: "datetime(6)", nullable: false) created_at = table.Column<DateTime>(type: "datetime(6)", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
@@ -568,12 +547,6 @@ namespace TechHelper.Server.Migrations
principalTable: "lesson", principalTable: "lesson",
principalColumn: "Id", principalColumn: "Id",
onDelete: ReferentialAction.SetNull); 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"); .Annotation("MySql:CharSet", "utf8mb4");
@@ -582,9 +555,14 @@ namespace TechHelper.Server.Migrations
columns: table => new columns: table => new
{ {
id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
question_id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), question_id = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
group_id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), assignment = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
title = table.Column<string>(type: "varchar(1024)", maxLength: 1024, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
description = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
question_number = table.Column<byte>(type: "tinyint unsigned", nullable: false), question_number = table.Column<byte>(type: "tinyint unsigned", nullable: false),
parent_question_group_id = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
group_state = table.Column<byte>(type: "tinyint unsigned", nullable: false),
created_at = table.Column<DateTime>(type: "datetime(6)", nullable: false), created_at = table.Column<DateTime>(type: "datetime(6)", nullable: false),
score = table.Column<float>(type: "float", nullable: true), score = table.Column<float>(type: "float", nullable: true),
deleted = table.Column<bool>(type: "tinyint(1)", nullable: false, defaultValue: false) deleted = table.Column<bool>(type: "tinyint(1)", nullable: false, defaultValue: false)
@@ -593,11 +571,21 @@ namespace TechHelper.Server.Migrations
{ {
table.PrimaryKey("PK_assignment_questions", x => x.id); table.PrimaryKey("PK_assignment_questions", x => x.id);
table.ForeignKey( table.ForeignKey(
name: "FK_assignment_questions_assignment_group_group_id", name: "FK_assignment_questions_QuestionContexts_description",
column: x => x.group_id, column: x => x.description,
principalTable: "assignment_group", principalTable: "QuestionContexts",
principalColumn: "id", principalColumn: "Id",
onDelete: ReferentialAction.Cascade); 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( table.ForeignKey(
name: "FK_assignment_questions_questions_question_id", name: "FK_assignment_questions_questions_question_id",
column: x => x.question_id, column: x => x.question_id,
@@ -655,9 +643,9 @@ namespace TechHelper.Server.Migrations
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,] values: new object[,]
{ {
{ new Guid("4e65fab9-3315-4474-b92c-bdab5a617e65"), null, "Administrator", "ADMINISTRATOR" }, { new Guid("04b04eed-32b9-4eb0-b5f5-a97bb4626718"), null, "Teacher", "TEACHER" },
{ new Guid("895d8f32-714e-4a14-bd97-8fa262b83172"), null, "Student", "STUDENT" }, { new Guid("577dbfe8-7b77-4ead-9386-678f02dea5f4"), null, "Student", "STUDENT" },
{ new Guid("d182c396-c656-42da-965a-d93c17a1f74f"), null, "Teacher", "TEACHER" } { new Guid("82354e4d-902d-4dd6-9790-6ef50ba9bc11"), null, "Administrator", "ADMINISTRATOR" }
}); });
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
@@ -708,20 +696,20 @@ namespace TechHelper.Server.Migrations
column: "class_id"); column: "class_id");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_assignment_group_assignment", name: "IX_assignment_questions_assignment",
table: "assignment_group", table: "assignment_questions",
column: "assignment", column: "assignment",
unique: true); unique: true);
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_assignment_group_parent_group", name: "IX_assignment_questions_description",
table: "assignment_group", table: "assignment_questions",
column: "parent_group"); column: "description");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_assignment_questions_group_id", name: "IX_assignment_questions_parent_question_group_id",
table: "assignment_questions", table: "assignment_questions",
column: "group_id"); column: "parent_question_group_id");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_assignment_questions_question_id", name: "IX_assignment_questions_question_id",
@@ -783,11 +771,6 @@ namespace TechHelper.Server.Migrations
table: "questions", table: "questions",
column: "lesson"); column: "lesson");
migrationBuilder.CreateIndex(
name: "IX_questions_parent_question_group_id",
table: "questions",
column: "parent_question_group_id");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_questions_question_text", name: "IX_questions_question_text",
table: "questions", table: "questions",
@@ -874,7 +857,7 @@ namespace TechHelper.Server.Migrations
name: "submissions"); name: "submissions");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "assignment_group"); name: "QuestionContexts");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "questions"); name: "questions");

View File

@@ -158,9 +158,9 @@ namespace TechHelper.Server.Migrations
.HasColumnType("char(36)") .HasColumnType("char(36)")
.HasColumnName("id"); .HasColumnName("id");
b.Property<Guid>("AssignmentGroupId") b.Property<Guid?>("AssignmentId")
.HasColumnType("char(36)") .HasColumnType("char(36)")
.HasColumnName("group_id"); .HasColumnName("assignment");
b.Property<DateTime>("CreatedAt") b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)") .HasColumnType("datetime(6)")
@@ -176,7 +176,15 @@ namespace TechHelper.Server.Migrations
.HasDefaultValue(false) .HasDefaultValue(false)
.HasColumnName("deleted"); .HasColumnName("deleted");
b.Property<Guid>("QuestionId") b.Property<Guid?>("ParentAssignmentQuestionId")
.HasColumnType("char(36)")
.HasColumnName("parent_question_group_id");
b.Property<Guid?>("QuestionContextId")
.HasColumnType("char(36)")
.HasColumnName("description");
b.Property<Guid?>("QuestionId")
.HasColumnType("char(36)") .HasColumnType("char(36)")
.HasColumnName("question_id"); .HasColumnName("question_id");
@@ -184,58 +192,13 @@ namespace TechHelper.Server.Migrations
.HasColumnType("float") .HasColumnType("float")
.HasColumnName("score"); .HasColumnName("score");
b.HasKey("Id"); b.Property<byte>("StructType")
b.HasIndex("AssignmentGroupId");
b.HasIndex("QuestionId");
b.ToTable("assignment_questions", (string)null);
});
modelBuilder.Entity("Entities.Contracts.AssignmentStruct", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)")
.HasColumnName("id");
b.Property<Guid?>("AssignmentId")
.HasColumnType("char(36)")
.HasColumnName("assignment");
b.Property<string>("Description")
.IsRequired()
.HasMaxLength(65535)
.HasColumnType("longtext")
.HasColumnName("descript");
b.Property<byte>("Index")
.HasColumnType("tinyint unsigned") .HasColumnType("tinyint unsigned")
.HasColumnName("number"); .HasColumnName("group_state");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("tinyint(1)")
.HasDefaultValue(false)
.HasColumnName("deleted");
b.Property<byte>("Layout")
.HasColumnType("tinyint unsigned")
.HasColumnName("layout");
b.Property<Guid?>("ParentGroupId")
.HasColumnType("char(36)")
.HasColumnName("parent_group");
b.Property<float?>("Score")
.HasColumnType("float")
.HasColumnName("total_points");
b.Property<string>("Title") b.Property<string>("Title")
.IsRequired() .HasMaxLength(1024)
.HasMaxLength(65535) .HasColumnType("varchar(1024)")
.HasColumnType("longtext")
.HasColumnName("title"); .HasColumnName("title");
b.HasKey("Id"); b.HasKey("Id");
@@ -243,9 +206,13 @@ namespace TechHelper.Server.Migrations
b.HasIndex("AssignmentId") b.HasIndex("AssignmentId")
.IsUnique(); .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 => modelBuilder.Entity("Entities.Contracts.Class", b =>
@@ -405,6 +372,7 @@ namespace TechHelper.Server.Migrations
b.Property<string>("Question") b.Property<string>("Question")
.IsRequired() .IsRequired()
.HasMaxLength(65535)
.HasColumnType("longtext"); .HasColumnType("longtext");
b.HasKey("Id"); b.HasKey("Id");
@@ -442,10 +410,6 @@ namespace TechHelper.Server.Migrations
.HasColumnType("tinyint unsigned") .HasColumnType("tinyint unsigned")
.HasColumnName("difficulty_level"); .HasColumnName("difficulty_level");
b.Property<byte>("GroupState")
.HasColumnType("tinyint unsigned")
.HasColumnName("group_state");
b.Property<bool>("IsDeleted") b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("tinyint(1)") .HasColumnType("tinyint(1)")
@@ -464,10 +428,6 @@ namespace TechHelper.Server.Migrations
.HasColumnType("longtext") .HasColumnType("longtext")
.HasColumnName("options"); .HasColumnName("options");
b.Property<Guid?>("ParentQuestionId")
.HasColumnType("char(36)")
.HasColumnName("parent_question_group_id");
b.Property<byte>("SubjectArea") b.Property<byte>("SubjectArea")
.HasMaxLength(100) .HasMaxLength(100)
.HasColumnType("tinyint unsigned") .HasColumnType("tinyint unsigned")
@@ -498,14 +458,27 @@ namespace TechHelper.Server.Migrations
b.HasIndex("LessonId"); b.HasIndex("LessonId");
b.HasIndex("ParentQuestionId");
b.HasIndex("Title") b.HasIndex("Title")
.HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 });
b.ToTable("questions", (string)null); b.ToTable("questions", (string)null);
}); });
modelBuilder.Entity("Entities.Contracts.QuestionContext", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("QuestionContexts");
});
modelBuilder.Entity("Entities.Contracts.Submission", b => modelBuilder.Entity("Entities.Contracts.Submission", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@@ -771,19 +744,19 @@ namespace TechHelper.Server.Migrations
b.HasData( b.HasData(
new new
{ {
Id = new Guid("895d8f32-714e-4a14-bd97-8fa262b83172"), Id = new Guid("577dbfe8-7b77-4ead-9386-678f02dea5f4"),
Name = "Student", Name = "Student",
NormalizedName = "STUDENT" NormalizedName = "STUDENT"
}, },
new new
{ {
Id = new Guid("d182c396-c656-42da-965a-d93c17a1f74f"), Id = new Guid("04b04eed-32b9-4eb0-b5f5-a97bb4626718"),
Name = "Teacher", Name = "Teacher",
NormalizedName = "TEACHER" NormalizedName = "TEACHER"
}, },
new new
{ {
Id = new Guid("4e65fab9-3315-4474-b92c-bdab5a617e65"), Id = new Guid("82354e4d-902d-4dd6-9790-6ef50ba9bc11"),
Name = "Administrator", Name = "Administrator",
NormalizedName = "ADMINISTRATOR" NormalizedName = "ADMINISTRATOR"
}); });
@@ -939,37 +912,31 @@ namespace TechHelper.Server.Migrations
modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b =>
{ {
b.HasOne("Entities.Contracts.AssignmentStruct", "AssignmentGroup") b.HasOne("Entities.Contracts.Assignment", "Assignment")
.WithMany("AssignmentQuestions") .WithOne("ExamStruct")
.HasForeignKey("AssignmentGroupId") .HasForeignKey("Entities.Contracts.AssignmentQuestion", "AssignmentId");
.OnDelete(DeleteBehavior.Cascade)
.IsRequired(); 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") b.HasOne("Entities.Contracts.Question", "Question")
.WithMany("AssignmentQuestions") .WithMany("AssignmentQuestions")
.HasForeignKey("QuestionId") .HasForeignKey("QuestionId")
.OnDelete(DeleteBehavior.Cascade) .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);
b.Navigation("Assignment"); b.Navigation("Assignment");
b.Navigation("ParentGroup"); b.Navigation("ParentAssignmentQuestion");
b.Navigation("Question");
b.Navigation("QuestionContext");
}); });
modelBuilder.Entity("Entities.Contracts.Class", b => modelBuilder.Entity("Entities.Contracts.Class", b =>
@@ -1072,18 +1039,11 @@ namespace TechHelper.Server.Migrations
.HasForeignKey("LessonId") .HasForeignKey("LessonId")
.OnDelete(DeleteBehavior.SetNull); .OnDelete(DeleteBehavior.SetNull);
b.HasOne("Entities.Contracts.Question", "ParentQuestion")
.WithMany("ChildrenQuestion")
.HasForeignKey("ParentQuestionId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Creator"); b.Navigation("Creator");
b.Navigation("KeyPoint"); b.Navigation("KeyPoint");
b.Navigation("Lesson"); b.Navigation("Lesson");
b.Navigation("ParentQuestion");
}); });
modelBuilder.Entity("Entities.Contracts.Submission", b => modelBuilder.Entity("Entities.Contracts.Submission", b =>
@@ -1204,16 +1164,11 @@ namespace TechHelper.Server.Migrations
modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b =>
{ {
b.Navigation("ChildrenAssignmentQuestion");
b.Navigation("SubmissionDetails"); b.Navigation("SubmissionDetails");
}); });
modelBuilder.Entity("Entities.Contracts.AssignmentStruct", b =>
{
b.Navigation("AssignmentQuestions");
b.Navigation("ChildrenGroups");
});
modelBuilder.Entity("Entities.Contracts.Class", b => modelBuilder.Entity("Entities.Contracts.Class", b =>
{ {
b.Navigation("AssignmentClasses"); b.Navigation("AssignmentClasses");
@@ -1240,8 +1195,11 @@ namespace TechHelper.Server.Migrations
modelBuilder.Entity("Entities.Contracts.Question", b => modelBuilder.Entity("Entities.Contracts.Question", b =>
{ {
b.Navigation("AssignmentQuestions"); b.Navigation("AssignmentQuestions");
});
b.Navigation("ChildrenQuestion"); modelBuilder.Entity("Entities.Contracts.QuestionContext", b =>
{
b.Navigation("Questions");
}); });
modelBuilder.Entity("Entities.Contracts.Submission", b => modelBuilder.Entity("Entities.Contracts.Submission", b =>

View File

@@ -27,12 +27,12 @@ builder.Services.AddDbContext<ApplicationContext>(options =>
).AddUnitOfWork<ApplicationContext>() ).AddUnitOfWork<ApplicationContext>()
.AddCustomRepository<Assignment, AssignmentRepository>() .AddCustomRepository<Assignment, AssignmentRepository>()
.AddCustomRepository<AssignmentAttachment, AssignmentAttachmentRepository>() .AddCustomRepository<AssignmentAttachment, AssignmentAttachmentRepository>()
.AddCustomRepository<AssignmentStruct, AssignmentGroupRepository>()
.AddCustomRepository<AssignmentQuestion, AssignmentQuestionRepository>() .AddCustomRepository<AssignmentQuestion, AssignmentQuestionRepository>()
.AddCustomRepository<Class, ClassRepository>() .AddCustomRepository<Class, ClassRepository>()
.AddCustomRepository<ClassStudent, ClassStudentRepository>() .AddCustomRepository<ClassStudent, ClassStudentRepository>()
.AddCustomRepository<ClassTeacher, ClassTeacherRepository>() .AddCustomRepository<ClassTeacher, ClassTeacherRepository>()
.AddCustomRepository<Question, QuestionRepository>() .AddCustomRepository<Question, QuestionRepository>()
.AddCustomRepository<QuestionContext, QuestionContextRepository>()
.AddCustomRepository<Submission, SubmissionRepository>(); .AddCustomRepository<Submission, SubmissionRepository>();
builder.Services.AddAutoMapper(typeof(AutoMapperProFile).Assembly); builder.Services.AddAutoMapper(typeof(AutoMapperProFile).Assembly);

View File

@@ -10,14 +10,12 @@ namespace TechHelper.Server.Repositories
{ {
private readonly IUnitOfWork _unitOfWork; private readonly IUnitOfWork _unitOfWork;
private readonly IRepository<Assignment> _assignmentRepo; private readonly IRepository<Assignment> _assignmentRepo;
private readonly IRepository<AssignmentStruct> _assignmentGroupRepo;
private readonly IRepository<Question> _questionRepo; private readonly IRepository<Question> _questionRepo;
public ExamRepository(IUnitOfWork unitOfWork) public ExamRepository(IUnitOfWork unitOfWork)
{ {
_unitOfWork = unitOfWork; _unitOfWork = unitOfWork;
_assignmentRepo = _unitOfWork.GetRepository<Assignment>(); _assignmentRepo = _unitOfWork.GetRepository<Assignment>();
_assignmentGroupRepo = _unitOfWork.GetRepository<AssignmentStruct>();
} }
public async Task<Assignment?> GetFullExamByIdAsync(Guid assignmentId) public async Task<Assignment?> 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<IEnumerable<Assignment>> GetExamPreviewsByUserAsync(Guid userId) public async Task<IEnumerable<Assignment>> GetExamPreviewsByUserAsync(Guid userId)
{ {
@@ -72,11 +47,6 @@ namespace TechHelper.Server.Repositories
} }
} }
public async Task AddAsync(AssignmentStruct assignment)
{
}
public async Task AddAsync(AssignmentQuestion assignment) public async Task AddAsync(AssignmentQuestion assignment)
{ {
} }

View File

@@ -26,7 +26,6 @@ namespace TechHelper.Server.Repositories
Task AddAsync(AssignmentStruct assignment);
Task AddAsync(AssignmentQuestion assignment); Task AddAsync(AssignmentQuestion assignment);

View File

@@ -5,10 +5,13 @@ using TechHelper.Context;
namespace TechHelper.Repository namespace TechHelper.Repository
{ {
public class AssignmentGroupRepository : Repository<AssignmentStruct>, IRepository<AssignmentStruct> public class QuestionContextRepository : Repository<QuestionContext>, IRepository<QuestionContext>
{ {
public AssignmentGroupRepository(ApplicationContext dbContext) : base(dbContext) public QuestionContextRepository(ApplicationContext dbContext) : base(dbContext)
{ {
} }
} }
} }

View File

@@ -25,87 +25,43 @@ namespace TechHelper.Server.Services
public async Task<ApiResponse> CreateExamAsync(AssignmentDto assignmentDto) public async Task<ApiResponse> CreateExamAsync(AssignmentDto assignmentDto)
{ {
try
Assignment newAssi = _mapper.Map<Assignment>(assignmentDto);
await _examRepository.AddAsync(newAssi);
var context = _unitOfWork.GetDbContext<ApplicationContext>();
foreach (var entry in context.ChangeTracker.Entries())
{ {
if (entry.State == Microsoft.EntityFrameworkCore.EntityState.Added)
Assignment newAssi = _mapper.Map<Assignment>(assignmentDto);
await _examRepository.AddAsync(newAssi);
var context = _unitOfWork.GetDbContext<ApplicationContext>();
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("保存失败");
} }
catch (Exception ex)
await _unitOfWork.SaveChangesAsync();
return ApiResponse.Success();
}
private async void ParseStruct(AssignmentStructDto assignmentStruct, Guid ParentID)
{
var newStruct = _mapper.Map<AssignmentStruct>(assignmentStruct);
newStruct.ParentStructId = Guid.Empty == ParentID ? null : ParentID;
await _examRepository.AddAsync(newStruct);
foreach (var item in assignmentStruct.AssignmentQuestions)
{ {
var newQuestion = _mapper.Map<Question>(item); return ApiResponse.Error(ex.Message);
//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);
} }
} }
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<AssignmentDto> GetExamByIdAsync(Guid id) public async Task<AssignmentDto> GetExamByIdAsync(Guid id)
{ {

View File

@@ -1,9 +0,0 @@
using Entities.Contracts;
using TechHelper.Services;
namespace TechHelper.Server.Services
{
public interface IAssignmentGroupService : IBaseService<AssignmentStruct, Guid>
{
}
}