struct&&assiQues
This commit is contained in:
77
Entities/Contracts/AppMainStruct.cs
Normal file
77
Entities/Contracts/AppMainStruct.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Entities.Contracts
|
||||
{
|
||||
public enum Layout : byte
|
||||
{
|
||||
horizontal = 0,
|
||||
vertical = 1,
|
||||
|
||||
Auto = 2
|
||||
}
|
||||
|
||||
public enum Publisher : byte
|
||||
{
|
||||
Unknown = 0,
|
||||
统编版,
|
||||
部编版,
|
||||
}
|
||||
|
||||
public enum Grade : byte
|
||||
{
|
||||
Unknown = 0,
|
||||
一年级 = 1,
|
||||
二年级 = 2,
|
||||
三年级 = 3,
|
||||
四年级 = 4,
|
||||
五年级 = 5,
|
||||
六年级 = 6
|
||||
}
|
||||
|
||||
public enum DifficultyLevel : byte
|
||||
{
|
||||
easy,
|
||||
medium,
|
||||
hard
|
||||
}
|
||||
|
||||
public enum QuestionType : byte
|
||||
{
|
||||
Unknown = 0,
|
||||
Spelling, // 拼写
|
||||
Pronunciation, // 给带点字选择正确读音
|
||||
WordFormation, // 组词
|
||||
FillInTheBlanks, // 选词填空 / 补充词语
|
||||
SentenceDictation, // 默写句子
|
||||
SentenceRewriting, // 仿句 / 改写句子
|
||||
ReadingComprehension, // 阅读理解
|
||||
Composition // 作文
|
||||
|
||||
}
|
||||
|
||||
public enum SubjectAreaEnum : byte
|
||||
{
|
||||
Unknown = 0,
|
||||
Mathematics, // 数学
|
||||
Physics, // 物理
|
||||
Chemistry, // 化学
|
||||
Biology, // 生物
|
||||
History, // 历史
|
||||
Geography, // 地理
|
||||
Literature, // 语文/文学
|
||||
English, // 英语
|
||||
ComputerScience, // 计算机科学
|
||||
}
|
||||
|
||||
public enum QuestionGroupState : byte
|
||||
{
|
||||
Standalone,
|
||||
Group,
|
||||
Subquestion
|
||||
}
|
||||
|
||||
}
|
@@ -24,32 +24,36 @@ namespace Entities.Contracts
|
||||
public string Description { get; set; }
|
||||
|
||||
[Column("subject_area")]
|
||||
public string SubjectArea { get; set; }
|
||||
public SubjectAreaEnum SubjectArea { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("due_date")]
|
||||
public DateTime DueDate { get; set; }
|
||||
|
||||
[Column("total_points")]
|
||||
public float? TotalPoints { get; set; }
|
||||
public byte TotalQuestions { get; set; }
|
||||
|
||||
[Column("score")]
|
||||
public float Score { get; set; }
|
||||
|
||||
[Column("created_by")]
|
||||
[ForeignKey("Creator")]
|
||||
public Guid CreatedBy { get; set; }
|
||||
public Guid CreatorId { get; set; }
|
||||
|
||||
[Column("created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
[Column("updated_at")]
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
[Column("deleted")]
|
||||
public bool IsDeleted { get; set; }
|
||||
public bool IsDeleted { get; set; } = false;
|
||||
|
||||
// Navigation Properties
|
||||
|
||||
[ForeignKey(nameof(CreatorId))]
|
||||
public User Creator { get; set; }
|
||||
public ICollection<AssignmentClass> AssignmentClasses { get; set; }
|
||||
public ICollection<AssignmentGroup> AssignmentGroups { get; set; }
|
||||
public AssignmentStruct ExamStruct { get; set; }
|
||||
public ICollection<AssignmentAttachment> AssignmentAttachments { get; set; }
|
||||
public ICollection<Submission> Submissions { get; set; }
|
||||
|
||||
@@ -58,7 +62,6 @@ namespace Entities.Contracts
|
||||
Id = Guid.NewGuid();
|
||||
|
||||
Submissions = new HashSet<Submission>();
|
||||
AssignmentGroups = new HashSet<AssignmentGroup>();
|
||||
AssignmentClasses = new HashSet<AssignmentClass>();
|
||||
AssignmentAttachments = new HashSet<AssignmentAttachment>();
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Entities.DTO;
|
||||
|
||||
namespace Entities.Contracts
|
||||
{
|
||||
@@ -17,41 +18,43 @@ namespace Entities.Contracts
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[Column("question_id")]
|
||||
public Guid? QuestionId { get; set; } // 设为可空
|
||||
|
||||
// 当 IsGroup 为 true 时,此为 QuestionGroup 的外键
|
||||
[Column("question_group_id")] // 新增一个外键列
|
||||
public Guid? QuestionGroupId { get; set; } // 设为可空
|
||||
public Guid QuestionId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("group_id")]
|
||||
[ForeignKey("AssignmentGroup")]
|
||||
public Guid AssignmentGroupId { get; set; }
|
||||
|
||||
public Guid AssignmentStructId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("question_number")]
|
||||
public byte QuestionNumber { get; set; }
|
||||
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;
|
||||
|
||||
[Column("created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
[Column("score")]
|
||||
public float? Score { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("bgroup")]
|
||||
public bool IsGroup { get; set; }
|
||||
|
||||
[Column("deleted")]
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
|
||||
public Question Question { get; set; }
|
||||
public QuestionGroup QuestionGroup { get; set; }
|
||||
public AssignmentStruct AssignmentStruct { get; set; }
|
||||
public ICollection<SubmissionDetail> SubmissionDetails { get; set; }
|
||||
public AssignmentGroup AssignmentGroup { get; set; }
|
||||
|
||||
[ForeignKey(nameof(ParentAssignmentQuestionId))]
|
||||
public AssignmentQuestion? ParentAssignmentQuestion { get; set; }
|
||||
public ICollection<AssignmentQuestion> ChildrenAssignmentQuestion { get; set; } = new List<AssignmentQuestion>();
|
||||
|
||||
|
||||
public AssignmentQuestion()
|
||||
{
|
||||
|
@@ -5,11 +5,12 @@ 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 AssignmentGroup
|
||||
public class AssignmentStruct
|
||||
{
|
||||
[Key]
|
||||
[Column("id")]
|
||||
@@ -26,35 +27,34 @@ namespace Entities.Contracts
|
||||
|
||||
[Column("descript")]
|
||||
[MaxLength(65535)]
|
||||
public string Descript { get; set; }
|
||||
public string Description { get; set; }
|
||||
|
||||
[Column("layout")]
|
||||
public Layout Layout { get; set; }
|
||||
|
||||
[Column("total_points")]
|
||||
public float? TotalPoints { get; set; }
|
||||
public float? Score { get; set; }
|
||||
|
||||
[Column("number")]
|
||||
public byte Number { get; set; }
|
||||
[Column("index")]
|
||||
public byte Index { get; set; }
|
||||
|
||||
[Column("parent_group")]
|
||||
public Guid? ParentGroup { get; set; }
|
||||
public Guid? ParentStructId { get; set; }
|
||||
|
||||
[Column("deleted")]
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
[Column("valid_question_group")]
|
||||
public bool ValidQuestionGroup { get; set; }
|
||||
public bool IsDeleted { get; set; } = false;
|
||||
|
||||
// Navigation Properties
|
||||
public Assignment? Assignment { get; set; }
|
||||
public AssignmentGroup? ParentAssignmentGroup { get; set;}
|
||||
public ICollection<AssignmentGroup> ChildAssignmentGroups { get; set; }
|
||||
public AssignmentStruct? ParentStruct { get; set;}
|
||||
public ICollection<AssignmentStruct> ChildrenGroups { get; set; }
|
||||
public ICollection<AssignmentQuestion> AssignmentQuestions { get; set; }
|
||||
|
||||
|
||||
public AssignmentGroup()
|
||||
public AssignmentStruct()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
ChildAssignmentGroups = new HashSet<AssignmentGroup>();
|
||||
ChildrenGroups = new HashSet<AssignmentStruct>();
|
||||
AssignmentQuestions = new HashSet<AssignmentQuestion>();
|
||||
}
|
||||
}
|
@@ -22,6 +22,6 @@ namespace Entities.Contracts
|
||||
public User Teacher { get; set; }
|
||||
|
||||
[Column("subject_taught")]
|
||||
public string SubjectTaught { get; set; }
|
||||
public SubjectAreaEnum SubjectTaught { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -16,36 +16,43 @@ namespace Entities.Contracts
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("question_text")]
|
||||
[Column("title")]
|
||||
[MaxLength(65535)]
|
||||
public string QuestionText { get; set; }
|
||||
public string Title { get; set; }
|
||||
|
||||
[Column("answer")]
|
||||
[MaxLength(65535)]
|
||||
public string? Answer { get; set; }
|
||||
|
||||
[Column("description")]
|
||||
public Guid? DescriptionId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("question_type")]
|
||||
[Column("type")]
|
||||
[MaxLength(20)]
|
||||
public QuestionType QuestionType { get; set; }
|
||||
|
||||
[Column("correct_answer")]
|
||||
[MaxLength(65535)]
|
||||
public string CorrectAnswer { get; set; }
|
||||
|
||||
[Column("question_group_id")]
|
||||
public Guid? QuestionGroupId { get; set; }
|
||||
public QuestionType Type { get; set; } = QuestionType.Unknown;
|
||||
|
||||
[Column("difficulty_level")]
|
||||
[MaxLength(10)]
|
||||
public DifficultyLevel DifficultyLevel { get; set; }
|
||||
public DifficultyLevel DifficultyLevel { get; set; } = DifficultyLevel.easy;
|
||||
|
||||
[Column("subject_area")]
|
||||
public SubjectAreaEnum SubjectArea { get; set; }
|
||||
public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown;
|
||||
|
||||
|
||||
[Column("options")]
|
||||
public string? Options { get; set; }
|
||||
|
||||
[Column("key_point")]
|
||||
public Guid? KeyPointId { get; set; }
|
||||
|
||||
[Column("lesson")]
|
||||
public Guid? LessonId { get; set; }
|
||||
|
||||
|
||||
[Required]
|
||||
[Column("created_by")]
|
||||
[ForeignKey("Creator")]
|
||||
public Guid CreatedBy { get; set; }
|
||||
public Guid CreatorId { get; set; }
|
||||
|
||||
[Column("created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
@@ -56,54 +63,30 @@ namespace Entities.Contracts
|
||||
[Column("deleted")]
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
[Column("valid_question")]
|
||||
public bool ValidQuestion { get; set; }
|
||||
|
||||
// Navigation Properties
|
||||
[ForeignKey(nameof(CreatorId))]
|
||||
public User Creator { get; set; }
|
||||
public QuestionGroup QuestionGroup { get; set; }
|
||||
public ICollection<AssignmentQuestion> AssignmentQuestions { get; set; }
|
||||
|
||||
[ForeignKey(nameof(DescriptionId))]
|
||||
public QuestionContext Description { get; set; }
|
||||
public Question? ParentQuestion { get; set; }
|
||||
public ICollection<Question>? ChildrenQuestion { get; set; }
|
||||
|
||||
[ForeignKey(nameof(KeyPointId))]
|
||||
public KeyPoint? KeyPoint { get; set; }
|
||||
[ForeignKey(nameof(LessonId))]
|
||||
public Lesson? Lesson { get; set; }
|
||||
|
||||
public ICollection<AssignmentQuestion>? AssignmentQuestions { get; set; }
|
||||
|
||||
public Question()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
AssignmentQuestions = new HashSet<AssignmentQuestion>();
|
||||
ChildrenQuestion = new HashSet<Question>();
|
||||
}
|
||||
}
|
||||
|
||||
public enum DifficultyLevel
|
||||
{
|
||||
easy,
|
||||
medium,
|
||||
hard
|
||||
}
|
||||
|
||||
public enum QuestionType
|
||||
{
|
||||
Unknown, // 可以有一个未知类型或作为默认
|
||||
Spelling, // 拼写
|
||||
Pronunciation, // 给带点字选择正确读音
|
||||
WordFormation, // 组词
|
||||
FillInTheBlanks, // 选词填空 / 补充词语
|
||||
SentenceDictation, // 默写句子
|
||||
SentenceRewriting, // 仿句 / 改写句子
|
||||
ReadingComprehension, // 阅读理解
|
||||
Composition // 作文
|
||||
// ... 添加您其他题目类型
|
||||
}
|
||||
|
||||
public enum SubjectAreaEnum // 建议命名为 SubjectAreaEnum 以避免与属性名冲突
|
||||
{
|
||||
Unknown, // 未知或默认
|
||||
Mathematics, // 数学
|
||||
Physics, // 物理
|
||||
Chemistry, // 化学
|
||||
Biology, // 生物
|
||||
History, // 历史
|
||||
Geography, // 地理
|
||||
Literature, // 语文/文学
|
||||
English, // 英语
|
||||
ComputerScience, // 计算机科学
|
||||
// ... 你可以根据需要添加更多科目
|
||||
}
|
||||
}
|
||||
|
25
Entities/Contracts/QuestionContext.cs
Normal file
25
Entities/Contracts/QuestionContext.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Entities.Contracts
|
||||
{
|
||||
public class QuestionContext
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[InverseProperty(nameof(Question.Description))]
|
||||
public ICollection<Question> Questions { get; set; } = new List<Question>();
|
||||
|
||||
|
||||
public QuestionContext()
|
||||
{
|
||||
Questions = new HashSet<Question>();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,79 +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;
|
||||
|
||||
namespace Entities.Contracts
|
||||
{
|
||||
[Table("question_groups")]
|
||||
public class QuestionGroup
|
||||
{
|
||||
[Key]
|
||||
[Column("id")]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[Column("title")]
|
||||
[MaxLength(255)]
|
||||
public string Title { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("description")]
|
||||
[MaxLength(65535)]
|
||||
public string Description { get; set; }
|
||||
|
||||
[Column("type")]
|
||||
[MaxLength(50)]
|
||||
public string Type { get; set; }
|
||||
|
||||
[Column("difficulty_level")]
|
||||
[MaxLength(10)]
|
||||
public DifficultyLevel DifficultyLevel { get; set; }
|
||||
|
||||
[Column("subject_area")]
|
||||
public SubjectAreaEnum SubjectArea { get; set; }
|
||||
|
||||
[Column("total_questions")]
|
||||
public int TotalQuestions { get; set; } = 0;
|
||||
|
||||
[Column("parent_question_group")]
|
||||
public Guid? ParentQG { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("created_by")]
|
||||
[ForeignKey("Creator")]
|
||||
public Guid CreatedBy { get; set; }
|
||||
|
||||
[Column("created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
[Column("updated_at")]
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
|
||||
[Column("deleted")]
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
[Column("valid_group")]
|
||||
public bool ValidGroup { get; set; }
|
||||
|
||||
|
||||
|
||||
public User Creator { get; set; }
|
||||
public QuestionGroup ParentQuestionGroup { get; set; }
|
||||
public ICollection<QuestionGroup> ChildQuestionGroups { get; set; }
|
||||
public ICollection<AssignmentQuestion> AssignmentQuestions { get; set; }
|
||||
public ICollection<Question> Questions { get; set; }
|
||||
|
||||
public QuestionGroup()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
Questions = new HashSet<Question>();
|
||||
CreatedAt = DateTime.UtcNow;
|
||||
UpdatedAt = DateTime.UtcNow;
|
||||
IsDeleted = false;
|
||||
ValidGroup = true;
|
||||
}
|
||||
}
|
||||
}
|
@@ -41,7 +41,7 @@ namespace Entities.Contracts
|
||||
|
||||
[Column("graded_by")]
|
||||
[ForeignKey("Grader")]
|
||||
public Guid? GradedBy { get; set; }
|
||||
public Guid? GraderId { get; set; }
|
||||
|
||||
[Column("graded_at")]
|
||||
public DateTime? GradedAt { get; set; }
|
||||
@@ -74,6 +74,5 @@ namespace Entities.Contracts
|
||||
Resubmission, // 待重新提交 (如果允许)
|
||||
Late, // 迟交
|
||||
Draft, // 草稿
|
||||
// ... 添加你需要的其他状态
|
||||
}
|
||||
}
|
||||
|
@@ -23,7 +23,6 @@ namespace Entities.Contracts
|
||||
|
||||
[Required]
|
||||
[Column("student_id")]
|
||||
[ForeignKey("User")]
|
||||
public Guid StudentId { get; set; }
|
||||
|
||||
[Required]
|
||||
@@ -52,8 +51,11 @@ namespace Entities.Contracts
|
||||
[Column("deleted")]
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
[ForeignKey(nameof(StudentId))]
|
||||
public User Student { get; set; }
|
||||
|
||||
public Submission Submission { get; set; }
|
||||
public User User { get; set; }
|
||||
|
||||
public AssignmentQuestion AssignmentQuestion { get; set; }
|
||||
|
||||
public SubmissionDetail()
|
||||
|
36
Entities/Contracts/Textbook/KeyPoint.cs
Normal file
36
Entities/Contracts/Textbook/KeyPoint.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Entities.Contracts
|
||||
{
|
||||
[Table("key_point")]
|
||||
public class KeyPoint
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[StringLength(255)]
|
||||
public string Key { get; set; } = string.Empty;
|
||||
|
||||
|
||||
[Required]
|
||||
public Guid LessonID { get; set; }
|
||||
|
||||
[ForeignKey(nameof(LessonID))]
|
||||
public Lesson Lesson { get; set; }
|
||||
|
||||
|
||||
public ICollection<Question> Questions { get; set; }
|
||||
|
||||
public KeyPoint()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
Questions = new HashSet<Question>();
|
||||
}
|
||||
}
|
||||
}
|
48
Entities/Contracts/Textbook/Lesson.cs
Normal file
48
Entities/Contracts/Textbook/Lesson.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Entities.Contracts
|
||||
{
|
||||
[Table("lesson")]
|
||||
public class Lesson
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[StringLength(255)]
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
public Guid TextbookID { get; set; }
|
||||
|
||||
|
||||
[ForeignKey(nameof(TextbookID))]
|
||||
public Textbook Textbook { get; set; }
|
||||
|
||||
[InverseProperty(nameof(KeyPoint.Lesson))]
|
||||
public ICollection<KeyPoint>? KeyPoints { get; set; }
|
||||
|
||||
[InverseProperty(nameof(Question.Lesson))]
|
||||
public ICollection<Question>? Questions { get; set; }
|
||||
|
||||
[InverseProperty(nameof(LessonQuestion.Lesson))]
|
||||
public ICollection<LessonQuestion>? LessonQuestions { get; set; }
|
||||
|
||||
|
||||
|
||||
public Lesson()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
KeyPoints = new HashSet<KeyPoint>();
|
||||
Questions = new HashSet<Question>();
|
||||
LessonQuestions = new HashSet<LessonQuestion>();
|
||||
}
|
||||
}
|
||||
}
|
32
Entities/Contracts/Textbook/LessonQuestion.cs
Normal file
32
Entities/Contracts/Textbook/LessonQuestion.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Entities.Contracts
|
||||
{
|
||||
[Table("lesson_question")]
|
||||
public class LessonQuestion
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[MaxLength(65535)]
|
||||
public string Question { get; set; }
|
||||
|
||||
[Required]
|
||||
public Guid LessonID { get; set; }
|
||||
|
||||
[ForeignKey(nameof(LessonID))]
|
||||
public Lesson Lesson { get; set; }
|
||||
|
||||
public LessonQuestion()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
36
Entities/Contracts/Textbook/Textbook.cs
Normal file
36
Entities/Contracts/Textbook/Textbook.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Entities.Contracts
|
||||
{
|
||||
[Table("textbook")]
|
||||
public class Textbook
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public Grade Grade { get; set; } = Grade.Unknown;
|
||||
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
public Publisher Publisher { get; set; } = Publisher.部编版;
|
||||
|
||||
public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown;
|
||||
|
||||
[InverseProperty(nameof(Lesson.Textbook))]
|
||||
public ICollection<Lesson> Lessons { get; set; }
|
||||
|
||||
public Textbook()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
Lessons = new HashSet<Lesson>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
9
Entities/DTO/AssignmentDto.cs
Normal file
9
Entities/DTO/AssignmentDto.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Entities.DTO
|
||||
{
|
||||
}
|
25
Entities/DTO/AssignmentQuestionDto.cs
Normal file
25
Entities/DTO/AssignmentQuestionDto.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Entities.Contracts;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Entities.DTO
|
||||
{
|
||||
public class AssignmentQuestionDto
|
||||
{
|
||||
public float Score { get; set; } = 0;
|
||||
public byte Index { get; set; } = 0;
|
||||
public QuestionGroupState GroupState { get; set; } = QuestionGroupState.Standalone;
|
||||
|
||||
|
||||
|
||||
public AssignmentQuestionDto? ParentAssignmentQuestion { get; set; }
|
||||
public ICollection<AssignmentQuestionDto> ChildrenAssignmentQuestion { get; set; } = new List<AssignmentQuestionDto>();
|
||||
|
||||
|
||||
|
||||
public QuestionDto Question { get; set; }
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Entities.Contracts;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -7,36 +8,88 @@ 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<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 Guid Id { get; set; } = Guid.Empty;
|
||||
public string Title { get; set; } = string.Empty;
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
public byte TotalQuestions { get; set; }
|
||||
public float Score { get; set; } = 0;
|
||||
public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown;
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
public DateTime DueDate { get; set; }
|
||||
public Guid CreatorId { get; set; }
|
||||
|
||||
public AssignmentStructDto ExamStruct { get; set; } = new AssignmentStructDto();
|
||||
}
|
||||
|
||||
public class AssignmentClassDto
|
||||
{
|
||||
public AssignmentDto Assignment { get; set; }
|
||||
public Class ClassId { get; set; }
|
||||
public DateTime AssignedAt { get; set; }
|
||||
}
|
||||
|
||||
public class QuestionContextDto
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.Empty;
|
||||
public string Description { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public class ExamDto
|
||||
{
|
||||
public Guid? AssignmentId { get; set; }
|
||||
public string CreaterEmail { get; set; }
|
||||
public string CreaterEmail { get; set; }
|
||||
public string AssignmentTitle { get; set; } = string.Empty;
|
||||
public string Description { get; set; }
|
||||
public string SubjectArea { get; set; }
|
||||
public QuestionGroupDto QuestionGroups { get; set; } = new QuestionGroupDto();
|
||||
public QuestionGroupDto ExamStruct { get; set; } = new QuestionGroupDto();
|
||||
}
|
||||
|
||||
public class QuestionGroupDto
|
||||
{
|
||||
public byte Index { get; set; }
|
||||
public byte Index { get; set; }
|
||||
|
||||
public string? Title { get; set; }
|
||||
|
||||
public float Score { get; set; }
|
||||
|
||||
public string? Descript { get; set; }
|
||||
public string? Descript { get; set; }
|
||||
public List<SubQuestionDto> SubQuestions { get; set; } = new List<SubQuestionDto>();
|
||||
public List<QuestionGroupDto> SubQuestionGroups { get; set; } = new List<QuestionGroupDto>();
|
||||
|
||||
// 标记是否是一个具有上下文的单独问题
|
||||
public bool ValidQuestionGroup { get; set; } = false;
|
||||
}
|
||||
|
||||
public class SubQuestionDto
|
||||
{
|
||||
|
||||
public byte Index { get; set; }
|
||||
public byte Index { get; set; }
|
||||
|
||||
public string? Stem { get; set; }
|
||||
|
||||
@@ -44,12 +97,11 @@ namespace Entities.DTO
|
||||
|
||||
public List<OptionDto> Options { get; set; } = new List<OptionDto>();
|
||||
|
||||
public string? SampleAnswer { get; set; }
|
||||
public string? SampleAnswer { get; set; }
|
||||
|
||||
public string? QuestionType { get; set; }
|
||||
public string? QuestionType { get; set; }
|
||||
public string? DifficultyLevel { get; set; }
|
||||
|
||||
// 标记是否是一个独立的问题
|
||||
public bool ValidQuestion { get; set; } = false;
|
||||
|
||||
}
|
||||
@@ -64,13 +116,13 @@ namespace Entities.DTO
|
||||
{
|
||||
public static void Convert(this ExamDto examDto)
|
||||
{
|
||||
var qg = examDto.QuestionGroups;
|
||||
var qg = examDto.ExamStruct;
|
||||
|
||||
}
|
||||
|
||||
public static void Convert(this QuestionGroupDto examDto)
|
||||
{
|
||||
if(examDto.ValidQuestionGroup)
|
||||
if (examDto.ValidQuestionGroup)
|
||||
{
|
||||
|
||||
}
|
||||
|
41
Entities/DTO/QuestionDto.cs
Normal file
41
Entities/DTO/QuestionDto.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Entities.Contracts;
|
||||
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;
|
||||
|
||||
namespace Entities.DTO
|
||||
{
|
||||
public class QuestionDto
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.Empty;
|
||||
|
||||
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;
|
||||
|
||||
public string? Options { get; set; }
|
||||
|
||||
public DifficultyLevel DifficultyLevel { get; set; } = DifficultyLevel.easy;
|
||||
|
||||
public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown;
|
||||
|
||||
public Guid CreatorId { get; set; }
|
||||
|
||||
public Guid? KeyPointId { get; set; }
|
||||
|
||||
public Guid? LessonId { get; set; }
|
||||
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.Now;
|
||||
|
||||
}
|
||||
}
|
@@ -1,67 +1,173 @@
|
||||
using Entities.DTO;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
using Entities.Contracts;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace TechHelper.Client.Exam
|
||||
{
|
||||
public class ParentStructInfo
|
||||
{
|
||||
public string Number { get; set; }
|
||||
public SubjectAreaEnum SubjectArea { get; set; }
|
||||
public byte Index { get; set; }
|
||||
}
|
||||
|
||||
public static class ExamPaperExtensions
|
||||
{
|
||||
public static ExamDto ConvertToExamDTO(this ExamPaper examPaper)
|
||||
public static AssignmentDto ConvertToExamDTO(this ExamPaper examPaper)
|
||||
{
|
||||
ExamDto dto = new ExamDto();
|
||||
AssignmentDto dto = new AssignmentDto();
|
||||
|
||||
dto.AssignmentTitle = examPaper.AssignmentTitle;
|
||||
dto.Title = examPaper.AssignmentTitle;
|
||||
dto.Description = examPaper.Description;
|
||||
dto.SubjectArea = examPaper.SubjectArea;
|
||||
dto.QuestionGroups.Title = examPaper.AssignmentTitle;
|
||||
dto.QuestionGroups.Descript = examPaper.Description;
|
||||
|
||||
var SubjectArea = SubjectAreaEnum.Literature;
|
||||
Enum.TryParse<SubjectAreaEnum>(examPaper.SubjectArea, out SubjectArea);
|
||||
dto.SubjectArea = SubjectArea;
|
||||
|
||||
AssignmentStructDto examStruct = new AssignmentStructDto();
|
||||
|
||||
foreach (var qg in examPaper.QuestionGroups)
|
||||
{
|
||||
var qgd = new QuestionGroupDto();
|
||||
ParseMajorQuestionGroup(qg, qgd, false);
|
||||
dto.QuestionGroups.SubQuestionGroups.Add(qgd);
|
||||
examStruct.ChildrenGroups.Add(ParseMajorQuestionGroup(qg));
|
||||
examStruct.ChildrenGroups.Last().Index = (byte)(examStruct.ChildrenGroups.Count());
|
||||
}
|
||||
|
||||
|
||||
foreach (var question in examPaper.TopLevelQuestions)
|
||||
{
|
||||
if (question.SubQuestions != null && question.SubQuestions.Any())
|
||||
{
|
||||
var qgDto = new QuestionGroupDto
|
||||
{
|
||||
Title = question.Stem,
|
||||
Score = (int)question.Score,
|
||||
Descript = "",
|
||||
};
|
||||
|
||||
qgDto.ValidQuestionGroup = !string.IsNullOrEmpty(qgDto.Descript);
|
||||
|
||||
|
||||
ParseQuestionWithSubQuestions(question, qgDto, qgDto.ValidQuestionGroup);
|
||||
dto.QuestionGroups.SubQuestionGroups.Add(qgDto);
|
||||
}
|
||||
else
|
||||
{
|
||||
var qgDto = new QuestionGroupDto
|
||||
{
|
||||
Title = question.Stem,
|
||||
Score = (int)question.Score,
|
||||
Descript = "",
|
||||
};
|
||||
|
||||
qgDto.ValidQuestionGroup = !string.IsNullOrEmpty(qgDto.Descript);
|
||||
|
||||
var subQuestionDto = new SubQuestionDto();
|
||||
ParseSingleQuestion(question, subQuestionDto, !qgDto.ValidQuestionGroup);
|
||||
qgDto.SubQuestions.Add(subQuestionDto);
|
||||
dto.QuestionGroups.SubQuestionGroups.Add(qgDto);
|
||||
}
|
||||
}
|
||||
dto.ExamStruct = examStruct;
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
private static AssignmentStructDto ParseMajorQuestionGroup(MajorQuestionGroup sqg)
|
||||
{
|
||||
var examStruct = new AssignmentStructDto();
|
||||
|
||||
if (sqg.SubQuestionGroups != null)
|
||||
{
|
||||
|
||||
examStruct.Title = sqg.Title;
|
||||
examStruct.Score = sqg.Score;
|
||||
examStruct.ChildrenGroups = new List<AssignmentStructDto>();
|
||||
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());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (sqg.SubQuestions != null)
|
||||
{
|
||||
|
||||
sqg.SubQuestions?.ForEach(sq =>
|
||||
{
|
||||
if(sq.SubQuestions.Any())
|
||||
{
|
||||
|
||||
}
|
||||
examStruct.AssignmentQuestions.Add(ParseAssignmentQuestion(sq));
|
||||
examStruct.AssignmentQuestions.Last().Index = (byte)(examStruct.AssignmentQuestions.Count());
|
||||
});
|
||||
}
|
||||
|
||||
return examStruct;
|
||||
}
|
||||
|
||||
|
||||
public static List<string> ParseOptionsFromText(this string optionsText)
|
||||
{
|
||||
return optionsText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)
|
||||
.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)
|
||||
{
|
||||
var aq = new AssignmentQuestionDto();
|
||||
aq.Score = sq.Score;
|
||||
|
||||
aq.Question = ParseQuestion(sq);
|
||||
|
||||
sq.SubQuestions?.ForEach(ssq =>
|
||||
{
|
||||
|
||||
aq.Question.ChildrenQuestion.Add(ParseQuestion(ssq));
|
||||
aq.Question.ChildrenQuestion.Last().Index = (byte)aq.Question.ChildrenQuestion.Count;
|
||||
|
||||
});
|
||||
|
||||
return aq;
|
||||
}
|
||||
|
||||
private static QuestionDto ParseQuestion(PaperQuestion sq)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
private static void ParseMajorQuestionGroup(MajorQuestionGroup qg, QuestionGroupDto qgd, bool isParentGroupValidChain)
|
||||
{
|
||||
qgd.Title = qg.Title;
|
||||
@@ -86,12 +192,10 @@ namespace TechHelper.Client.Exam
|
||||
});
|
||||
}
|
||||
|
||||
// 处理 MajorQuestionGroup 下的 SubQuestions
|
||||
if (qg.SubQuestions != null)
|
||||
{
|
||||
qg.SubQuestions.ForEach(sq =>
|
||||
{
|
||||
// 如果 MajorQuestionGroup 下的 Question 包含子问题,则转为 QuestionGroupDto
|
||||
if (sq.SubQuestions != null && sq.SubQuestions.Any())
|
||||
{
|
||||
var subQgd = new QuestionGroupDto
|
||||
@@ -101,7 +205,6 @@ namespace TechHelper.Client.Exam
|
||||
Score = (int)sq.Score,
|
||||
Descript = "" // 默认为空
|
||||
};
|
||||
// 判断当前组是否有效:如果有描述,并且其父级链中没有任何一个组是有效组,则当前组有效
|
||||
subQgd.ValidQuestionGroup = !string.IsNullOrEmpty(subQgd.Descript) && !nextIsParentGroupValidChain;
|
||||
|
||||
ParseQuestionWithSubQuestions(sq, subQgd, subQgd.ValidQuestionGroup || nextIsParentGroupValidChain);
|
||||
@@ -121,7 +224,7 @@ namespace TechHelper.Client.Exam
|
||||
|
||||
// 解析包含子问题的 Question,将其转换为 QuestionGroupDto
|
||||
// isParentGroupValidChain 参数表示从顶层到当前组的任一父组是否已经是“有效组”
|
||||
private static void ParseQuestionWithSubQuestions(Question question, QuestionGroupDto qgd, bool isParentGroupValidChain)
|
||||
private static void ParseQuestionWithSubQuestions(PaperQuestion question, QuestionGroupDto qgd, bool isParentGroupValidChain)
|
||||
{
|
||||
qgd.Title = question.Stem;
|
||||
qgd.Score = (int)question.Score;
|
||||
@@ -165,7 +268,7 @@ namespace TechHelper.Client.Exam
|
||||
}
|
||||
|
||||
// 解析单个 Question (没有子问题) 为 SubQuestionDto
|
||||
private static void ParseSingleQuestion(Question question, SubQuestionDto subQd, bool validQ)
|
||||
private static void ParseSingleQuestion(PaperQuestion question, SubQuestionDto subQd, bool validQ)
|
||||
{
|
||||
subQd.Stem = question.Stem;
|
||||
subQd.Score = (int)question.Score;
|
||||
@@ -187,7 +290,7 @@ namespace TechHelper.Client.Exam
|
||||
|
||||
public static void SeqIndex(this ExamDto dto)
|
||||
{
|
||||
dto.QuestionGroups.SeqQGroupIndex();
|
||||
dto.ExamStruct.SeqQGroupIndex();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -51,7 +51,7 @@ namespace TechHelper.Client.Exam
|
||||
public string Description { get; set; } = "未识别试卷描述";
|
||||
public string SubjectArea { get; set; } = "试卷类别";
|
||||
public List<MajorQuestionGroup> QuestionGroups { get; set; } = new List<MajorQuestionGroup>();
|
||||
public List<Question> TopLevelQuestions { get; set; } = new List<Question>();
|
||||
public List<PaperQuestion> TopLevelQuestions { get; set; } = new List<PaperQuestion>();
|
||||
public List<ParseError> Errors { get; set; } = new List<ParseError>();
|
||||
}
|
||||
|
||||
@@ -61,17 +61,18 @@ namespace TechHelper.Client.Exam
|
||||
public string Descript { get; set; } = string.Empty;
|
||||
public float Score { get; set; }
|
||||
public List<MajorQuestionGroup> SubQuestionGroups { get; set; } = new List<MajorQuestionGroup>();
|
||||
public List<Question> SubQuestions { get; set; } = new List<Question>();
|
||||
public List<PaperQuestion> SubQuestions { get; set; } = new List<PaperQuestion>();
|
||||
public int Priority { get; set; }
|
||||
public bool bGroup { get; set; } = true;
|
||||
}
|
||||
|
||||
public class Question
|
||||
public class PaperQuestion
|
||||
{
|
||||
public string Number { get; set; } = string.Empty;
|
||||
public string Stem { get; set; } = string.Empty;
|
||||
public float Score { get; set; }
|
||||
public List<Option> Options { get; set; } = new List<Option>();
|
||||
public List<Question> SubQuestions { get; set; } = new List<Question>();
|
||||
public List<PaperQuestion> SubQuestions { get; set; } = new List<PaperQuestion>();
|
||||
public string SampleAnswer { get; set; } = string.Empty;
|
||||
public string QuestionType { get; set; } = string.Empty;
|
||||
public int Priority { get; set; }
|
||||
@@ -120,17 +121,17 @@ namespace TechHelper.Client.Exam
|
||||
public ExamParserConfig()
|
||||
{
|
||||
MajorQuestionGroupPatterns.Add(new RegexPatternConfig(@"^([一二三四五六七八九十]+)[、\.]\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 1));
|
||||
MajorQuestionGroupPatterns.Add(new RegexPatternConfig(@"^\(([一二三四五六七八九十]{1,2}|十[一二三四五六七八九])\)\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 2));
|
||||
QuestionPatterns.Add(new RegexPatternConfig(@"^\(([一二三四五六七八九十]{1,2}|十[一二三四五六七八九])\)\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 1));
|
||||
|
||||
|
||||
// 模式 1: "1. 这是一个题目 (5分)" 或 "1. 这是一个题目"
|
||||
QuestionPatterns.Add(new RegexPatternConfig(@"^(\d+)\.\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 1));
|
||||
QuestionPatterns.Add(new RegexPatternConfig(@"^(\d+)\.\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 2));
|
||||
|
||||
// 模式 2: "(1) 这是一个子题目 (3分)" 或 "(1) 这是一个子题目"
|
||||
QuestionPatterns.Add(new RegexPatternConfig(@"^\((\d+)\)\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 2));
|
||||
QuestionPatterns.Add(new RegexPatternConfig(@"^\((\d+)\)\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 3));
|
||||
|
||||
// 模式 3: "① 这是一个更深层次的子题目 (2分)" 或 "① 这是一个更深层次的子题目"
|
||||
QuestionPatterns.Add(new RegexPatternConfig(@"^[①②③④⑤⑥⑦⑧⑨⑩]+\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 3));
|
||||
QuestionPatterns.Add(new RegexPatternConfig(@"^[①②③④⑤⑥⑦⑧⑨⑩]+\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 4));
|
||||
|
||||
|
||||
OptionPatterns.Add(new RegexPatternConfig(@"([A-Z]\.)\s*(.*?)(?=[A-Z]\.|$)", 1)); // 大写字母选项
|
||||
@@ -251,6 +252,23 @@ namespace TechHelper.Client.Exam
|
||||
_config = config ?? throw new ArgumentNullException(nameof(config), "ExamParserConfig cannot be null.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// 一.基础
|
||||
/// 1.听写
|
||||
/// 2.阅读
|
||||
/// 二.提升
|
||||
/// 1.阅读
|
||||
/// (1).选择
|
||||
/// (2).填空
|
||||
/// 三.写
|
||||
/// (一)课文
|
||||
///
|
||||
///
|
||||
///
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Builds the ExamPaper structure from raw text and potential matches.
|
||||
/// Collects and returns parsing errors encountered during the process.
|
||||
@@ -260,7 +278,7 @@ namespace TechHelper.Client.Exam
|
||||
/// <returns>An ExamPaper object containing the parsed structure and a list of errors.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown if fullExamText is null or empty.</exception>
|
||||
/// <exception cref="ArgumentNullException">Thrown if allPotentialMatches is null.</exception>
|
||||
public ExamPaper BuildExamPaper(string fullExamText, List<PotentialMatch> allPotentialMatches)
|
||||
public ExamPaper BuildExam(string fullExamText, List<PotentialMatch> allPotentialMatches)
|
||||
{
|
||||
// 核心输入验证仍然是必要的,因为这些错误是无法恢复的
|
||||
if (string.IsNullOrWhiteSpace(fullExamText))
|
||||
@@ -289,8 +307,8 @@ namespace TechHelper.Client.Exam
|
||||
var majorQGStack = new Stack<MajorQuestionGroup>();
|
||||
MajorQuestionGroup currentMajorQG = null;
|
||||
|
||||
var questionStack = new Stack<Question>();
|
||||
Question currentQuestion = null;
|
||||
var questionStack = new Stack<PaperQuestion>();
|
||||
PaperQuestion currentQuestion = null;
|
||||
|
||||
int currentContentStart = 0;
|
||||
|
||||
@@ -388,6 +406,7 @@ namespace TechHelper.Client.Exam
|
||||
Title = pm.RegexMatch.Groups[2].Value.Trim(), // 标题是 Group 2
|
||||
Score = score,
|
||||
Priority = pm.PatternConfig.Priority,
|
||||
bGroup = true
|
||||
};
|
||||
|
||||
if (majorQGStack.Any())
|
||||
@@ -446,7 +465,7 @@ namespace TechHelper.Client.Exam
|
||||
}
|
||||
}
|
||||
|
||||
Question newQuestion = new Question
|
||||
PaperQuestion newQuestion = new PaperQuestion
|
||||
{
|
||||
Number = pm.RegexMatch.Groups[1].Value.Trim(),
|
||||
Stem = pm.RegexMatch.Groups[2].Value.Trim(),
|
||||
@@ -618,7 +637,7 @@ namespace TechHelper.Client.Exam
|
||||
/// Processes the content of a Question, mainly for parsing Options and identifying unstructured text.
|
||||
/// Logs errors to the provided error list instead of throwing.
|
||||
/// </summary>
|
||||
private void ProcessQuestionContent(Question question, string contentText, List<PotentialMatch> potentialMatchesInScope, List<ParseError> errors)
|
||||
private void ProcessQuestionContent(PaperQuestion question, string contentText, List<PotentialMatch> potentialMatchesInScope, List<ParseError> errors)
|
||||
{
|
||||
// 参数验证,这些是内部方法的契约,如果违反则直接抛出,因为这意味着调用者有错
|
||||
if (question == null) throw new ArgumentNullException(nameof(question), "Question cannot be null in ProcessQuestionContent.");
|
||||
@@ -674,8 +693,10 @@ namespace TechHelper.Client.Exam
|
||||
question.Options.Add(newOption);
|
||||
lastOptionEndIndex = pm.EndIndex;
|
||||
}
|
||||
// TODO: If there are SubQuestion types, they can be processed similarly here.
|
||||
// 你可以在此处添加对子问题的处理逻辑,同样需要小心处理其内容和嵌套。
|
||||
else
|
||||
{
|
||||
question.Stem += contentText;
|
||||
}
|
||||
}
|
||||
catch (Exception innerEx)
|
||||
{
|
||||
@@ -734,7 +755,7 @@ namespace TechHelper.Client.Exam
|
||||
// 2. 构建:根据扫描结果和原始文本,线性遍历并构建层级结构
|
||||
// BuildExamPaper 现在会返回一个包含错误列表的 ExamPaper 对象
|
||||
// 外部不再需要捕获内部解析异常,只需检查 ExamPaper.Errors 列表
|
||||
return _builder.BuildExamPaper(examPaperText, allPotentialMatches);
|
||||
return _builder.BuildExam(examPaperText, allPotentialMatches);
|
||||
}
|
||||
}
|
||||
}
|
@@ -52,7 +52,7 @@ namespace TechHelper.Client.Exam
|
||||
Title = dto.AssignmentTitle
|
||||
};
|
||||
|
||||
GetSeqRecursive(dto.QuestionGroups, null, examStruct.Questions);
|
||||
GetSeqRecursive(dto.ExamStruct, null, examStruct.Questions);
|
||||
|
||||
return examStruct;
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
@using Entities.DTO
|
||||
@using TechHelper.Client.Exam
|
||||
@using TechHelper.Client.Services
|
||||
@page "/exam/check/{ExamID}"
|
||||
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
@page "/exam/create"
|
||||
@using TechHelper.Client.Services
|
||||
@using Blazored.TextEditor
|
||||
@using Entities.DTO
|
||||
@using TechHelper.Client.Exam
|
||||
@@ -82,7 +83,7 @@
|
||||
}
|
||||
private BlazoredTextEditor _textEditor = new BlazoredTextEditor();
|
||||
private ExamPaper _parsedExam = new ExamPaper();
|
||||
private ExamDto ExamContent = new ExamDto();
|
||||
private AssignmentDto ExamContent = new AssignmentDto();
|
||||
|
||||
private ExamParserConfig _examParserConfig { get; set; } = new ExamParserConfig();
|
||||
|
||||
@@ -101,7 +102,7 @@
|
||||
Snackbar.Add("试卷解析成功。", Severity.Success);
|
||||
Snackbar.Add($"{_parsedExam.Errors}。", Severity.Success);
|
||||
ExamContent = _parsedExam.ConvertToExamDTO();
|
||||
ExamContent.SeqIndex();
|
||||
// ExamContent.SeqIndex();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -125,7 +126,6 @@
|
||||
|
||||
public async Task Publish()
|
||||
{
|
||||
ExamContent.CreaterEmail = authenticationStateTask.Result.User.Identity.Name;
|
||||
var apiRespon = await examService.SaveParsedExam(ExamContent);
|
||||
Snackbar.Add(apiRespon.Message);
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
@page "/exam/edit/{ExamId}"
|
||||
@using Entities.DTO
|
||||
@using TechHelper.Client.Services
|
||||
@using Entities.DTO
|
||||
@using TechHelper.Client.Exam
|
||||
|
||||
<ExamView ParsedExam="@ExamDto"/>
|
||||
@@ -17,7 +19,7 @@
|
||||
[Inject]
|
||||
private ISnackbar Snackbar { get; set; }
|
||||
|
||||
private ExamDto ExamDto { get; set; }
|
||||
private AssignmentDto ExamDto { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
@@ -27,8 +29,8 @@
|
||||
Console.WriteLine($"ExamId 字符串成功解析为 Guid: {parsedExamId}");
|
||||
try
|
||||
{
|
||||
var result = await ExamService.GetExam(parsedExamId);
|
||||
if (result.Status) ExamDto = result.Result as ExamDto ?? new ExamDto();
|
||||
// var result = await ExamService.GetExam(parsedExamId);
|
||||
// if (result.Status) ExamDto = result.Result as ExamDto ?? new ExamDto();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@@ -4,41 +4,29 @@
|
||||
|
||||
<MudPaper Elevation=@Elevation Class=@Class>
|
||||
|
||||
@foreach (var majorQG in MajorQGList)
|
||||
{
|
||||
<MudStack Row="true">
|
||||
<MudText Typo="Typo.h6">@majorQG.Title</MudText>
|
||||
@if (majorQG.Score > 0)
|
||||
<MudStack Row="true">
|
||||
<MudText Typo="Typo.h6">@ExamStruct.Title</MudText>
|
||||
@if (ExamStruct.Score > 0)
|
||||
{
|
||||
<MudText Typo="Typo.body2"><b>总分:</b> @majorQG.Score 分</MudText>
|
||||
<MudText Typo="Typo.body2"><b>总分:</b> @ExamStruct.Score 分</MudText>
|
||||
}
|
||||
</MudStack>
|
||||
|
||||
@foreach (var childStruct in ExamStruct.ChildrenGroups)
|
||||
{
|
||||
<ExamGroupView ExamStruct="childStruct"/>
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(majorQG.Descript))
|
||||
{
|
||||
<MudText Typo="Typo.body2">@((MarkupString)majorQG.Descript.Replace("\n", "<br />"))</MudText>
|
||||
}
|
||||
|
||||
@if (majorQG.SubQuestions.Any())
|
||||
{
|
||||
@foreach (var question in majorQG.SubQuestions)
|
||||
{
|
||||
<QuestionCard Question="question" Elevation=@Elevation Class="my-2 pa-1" />
|
||||
}
|
||||
}
|
||||
|
||||
@if (majorQG.SubQuestionGroups.Any())
|
||||
{
|
||||
<ExamGroupView MajorQGList="majorQG.SubQuestionGroups" Elevation="1" />
|
||||
}
|
||||
@foreach (var question in ExamStruct.AssignmentQuestions)
|
||||
{
|
||||
<QuestionCard Question="question.Question" Elevation=@Elevation Class="my-2 pa-1" />
|
||||
}
|
||||
|
||||
</MudPaper>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public List<QuestionGroupDto> MajorQGList { get; set; } = new List<QuestionGroupDto>();
|
||||
public AssignmentStructDto ExamStruct { get; set; } = new AssignmentStructDto();
|
||||
|
||||
[Parameter]
|
||||
public string Class { get; set; } = "my-2 pa-1";
|
||||
|
@@ -4,6 +4,8 @@
|
||||
|
||||
|
||||
@page "/exam/manage"
|
||||
@using Entities.DTO
|
||||
@using TechHelper.Client.Services
|
||||
@attribute [Authorize]
|
||||
|
||||
|
||||
|
@@ -5,10 +5,10 @@
|
||||
{
|
||||
|
||||
<MudPaper Height="@Height" Class="@Class" Style="@Style" Width="@Width">
|
||||
<MudText Class="d-flex justify-content-center" Typo="Typo.h6"> @ParsedExam.AssignmentTitle </MudText>
|
||||
<MudText Class="d-flex justify-content-center" Typo="Typo.h6"> @ParsedExam.Title </MudText>
|
||||
<MudText Typo="Typo.body1"> @ParsedExam.Description </MudText>
|
||||
|
||||
<ExamGroupView MajorQGList="@ParsedExam.QuestionGroups.SubQuestionGroups" Elevation="1" Class="ma-0 pa-2" />
|
||||
<ExamGroupView ExamStruct="@ParsedExam.ExamStruct" Elevation="1" Class="ma-0 pa-2" />
|
||||
</MudPaper>
|
||||
|
||||
}
|
||||
@@ -24,7 +24,7 @@ else
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public ExamDto ParsedExam { get; set; } = new ExamDto();
|
||||
public AssignmentDto ParsedExam { get; set; } = new AssignmentDto();
|
||||
[Parameter]
|
||||
public string Height { get; set; } = "100%";
|
||||
[Parameter]
|
||||
|
@@ -4,29 +4,35 @@
|
||||
<MudPaper Class=@Class Elevation=@Elevation Outlined="false">
|
||||
|
||||
<MudText Typo="Typo.subtitle1">
|
||||
<b>@Question.Index</b> @((MarkupString)Question.Stem.Replace("\n", "<br />"))
|
||||
<b>@Question.Index</b> @((MarkupString)Question.Title.Replace("\n", "<br />"))
|
||||
@if (Question.Score > 0)
|
||||
{
|
||||
<MudText Typo="Typo.body2" Class="d-inline ml-2">(@Question.Score 分)</MudText>
|
||||
}
|
||||
</MudText>
|
||||
|
||||
@if (Question.Options.Any())
|
||||
@if (Question.Options != null)
|
||||
{
|
||||
<div class="mt-2">
|
||||
@foreach (var option in Question.Options)
|
||||
@foreach (var option in Question.Options.ParseOptionsFromText())
|
||||
{
|
||||
var tempOption = option;
|
||||
<p>@((MarkupString)(tempOption.Value.Replace("\n", "<br />")))</p>
|
||||
<p>@((MarkupString)(tempOption.Replace("\n", "<br />")))</p>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@foreach(var item in Question.ChildrenQuestion)
|
||||
{
|
||||
<QuestionCard Question="item"/>
|
||||
|
||||
}
|
||||
</MudPaper>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public SubQuestionDto Question { get; set; } = new SubQuestionDto();
|
||||
public QuestionDto Question { get; set; } = new QuestionDto();
|
||||
|
||||
[Parameter]
|
||||
public string Class { get; set; }
|
||||
|
@@ -13,7 +13,6 @@ using TechHelper.Client.Services;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
|
||||
using TechHelper.Client.AI;
|
||||
using TechHelper.Client.Exam;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
|
||||
|
@@ -3,9 +3,9 @@ using TechHelper.Client.AI;
|
||||
using TechHelper.Services;
|
||||
using Entities.DTO;
|
||||
using System.Net.Http.Json; // 用于 PostAsJsonAsync
|
||||
using Newtonsoft.Json; // 用于 JSON 反序列化
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace TechHelper.Client.Exam
|
||||
namespace TechHelper.Client.Services
|
||||
{
|
||||
public class ExamService : IExamService
|
||||
{
|
||||
@@ -144,10 +144,10 @@ namespace TechHelper.Client.Exam
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> SaveParsedExam(ExamDto examDto)
|
||||
public async Task<ApiResponse> SaveParsedExam(AssignmentDto assiDto)
|
||||
{
|
||||
// 直接使用注入的 _client 实例
|
||||
var response = await _client.PostAsJsonAsync("exam/add", examDto);
|
||||
var response = await _client.PostAsJsonAsync("exam/add", assiDto);
|
||||
|
||||
if (response.IsSuccessStatusCode) // 检查是否是成功的状态码,例如 200 OK, 201 Created 等
|
||||
{
|
@@ -1,13 +1,13 @@
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Client.Exam
|
||||
namespace TechHelper.Client.Services
|
||||
{
|
||||
public interface IExamService
|
||||
{
|
||||
public Task<ApiResponse> FormatExam(string examContent);
|
||||
public Task<ApiResponse> DividExam(string examContent);
|
||||
public Task<ApiResponse> SaveParsedExam(ExamDto examDto);
|
||||
public Task<ApiResponse> SaveParsedExam(AssignmentDto assiDto);
|
||||
public Task<ApiResponse> ParseSingleQuestionGroup(string examContent);
|
||||
public ApiResponse ConvertToXML<T>(string xmlContent);
|
||||
|
@@ -22,6 +22,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
||||
<PackageReference Include="Blazor.LocalStorage.WebAssembly" Version="8.0.0" />
|
||||
<PackageReference Include="Blazored.TextEditor" Version="1.1.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.12" />
|
||||
|
@@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Entities.Contracts;
|
||||
using TechHelper.Server.Context.Configuration;
|
||||
|
||||
namespace TechHelper.Context
|
||||
{
|
||||
@@ -36,7 +35,6 @@ namespace TechHelper.Context
|
||||
builder.ApplyConfiguration(new ClassTeacherConfiguration());
|
||||
builder.ApplyConfiguration(new QuestionConfiguration());
|
||||
builder.ApplyConfiguration(new SubmissionConfiguration());
|
||||
builder.ApplyConfiguration(new QuestionGroupConfiguration());
|
||||
builder.ApplyConfiguration(new SubmissionDetailConfiguration());
|
||||
}
|
||||
}
|
||||
|
@@ -36,60 +36,41 @@ namespace TechHelper.Context
|
||||
|
||||
CreateMap<SubQuestionDto, Question>()
|
||||
.ForMember(dest => dest.Id, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.QuestionText, opt => opt.MapFrom(src => src.Stem))
|
||||
.ForMember(dest => dest.CorrectAnswer, opt => opt.MapFrom(src => src.SampleAnswer))
|
||||
.ForMember(dest => dest.QuestionType, opt => opt.MapFrom(src => EnumMappingHelpers.ParseEnumSafe(src.QuestionType, QuestionType.Unknown)))
|
||||
.ForMember(dest => dest.Title, opt => opt.MapFrom(src => src.Stem))
|
||||
.ForMember(dest => dest.Answer, opt => opt.MapFrom(src => src.SampleAnswer))
|
||||
.ForMember(dest => dest.Type, opt => opt.MapFrom(src => EnumMappingHelpers.ParseEnumSafe(src.QuestionType, QuestionType.Unknown)))
|
||||
.ForMember(dest => dest.DifficultyLevel, opt => opt.MapFrom(src => EnumMappingHelpers.ParseEnumSafe(src.DifficultyLevel, DifficultyLevel.easy)))
|
||||
.ForMember(dest => dest.SubjectArea, opt => opt.MapFrom(src => EnumMappingHelpers.ParseEnumSafe(src.DifficultyLevel, SubjectAreaEnum.Unknown)))
|
||||
.ForMember(dest => dest.CreatedBy, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.CreatorId, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.CreatedAt, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.UpdatedAt, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.IsDeleted, opt => opt.Ignore());
|
||||
|
||||
// 2. Question -> SubQuestionDto (查看时)
|
||||
CreateMap<Question, SubQuestionDto>()
|
||||
.ForMember(dest => dest.Stem, opt => opt.MapFrom(src => src.QuestionText))
|
||||
.ForMember(dest => dest.Score, opt => opt.Ignore()) // Question 实体没有 Score 字段,需要从 AssignmentQuestion 获取
|
||||
.ForMember(dest => dest.SampleAnswer, opt => opt.MapFrom(src => src.CorrectAnswer))
|
||||
.ForMember(dest => dest.QuestionType, opt => opt.MapFrom(src => src.QuestionType.ToString()))
|
||||
.ForMember(dest => dest.DifficultyLevel, opt => opt.MapFrom(src => src.DifficultyLevel.ToString()))
|
||||
.ForMember(dest => dest.Options, opt => opt.Ignore()); // Options 需要单独处理
|
||||
|
||||
CreateMap<Assignment, ExamDto>()
|
||||
.ForMember(dest => dest.AssignmentTitle, opt => opt.MapFrom(src => src.Title))
|
||||
.ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description))
|
||||
.ForMember(dest => dest.AssignmentId, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(dest => dest.QuestionGroups, opt => opt.MapFrom(src =>
|
||||
src.AssignmentGroups.FirstOrDefault(ag => ag.ParentGroup == null)))
|
||||
.ForMember(dest => dest.SubjectArea, opt => opt.MapFrom(src => src.SubjectArea.ToString()));
|
||||
// =============================================================
|
||||
// ENTITY -> DTO Mappings (用于读取/查询)
|
||||
// =============================================================
|
||||
CreateMap<Assignment, AssignmentDto>()
|
||||
.ForMember(dest => dest.ExamStruct, opt => opt.MapFrom(src => src.ExamStruct));
|
||||
|
||||
CreateMap<AssignmentGroup, QuestionGroupDto>()
|
||||
.ForMember(dest => dest.SubQuestionGroups, opt => opt.MapFrom(src => src.ChildAssignmentGroups))
|
||||
.ForMember(dest => dest.SubQuestions, opt => opt.MapFrom(src => src.AssignmentQuestions));
|
||||
CreateMap<AssignmentStruct, AssignmentStructDto>(); // 直接映射,因为成员现在对等了
|
||||
|
||||
CreateMap<AssignmentQuestion, SubQuestionDto>()
|
||||
.ForMember(dest => dest.Stem, opt => opt.MapFrom(src => src.Question.QuestionText))
|
||||
.ForMember(dest => dest.SampleAnswer, opt => opt.MapFrom(src => src.Question.CorrectAnswer))
|
||||
.ForMember(dest => dest.QuestionType, opt => opt.MapFrom(src => src.Question.QuestionType.ToString()))
|
||||
.ForMember(dest => dest.DifficultyLevel, opt => opt.MapFrom(src => src.Question.DifficultyLevel.ToString()));
|
||||
// 新增!从实体到新的 DTO 的映射
|
||||
CreateMap<AssignmentQuestion, AssignmentQuestionDto>();
|
||||
|
||||
CreateMap<Question, QuestionDto>();
|
||||
|
||||
// =================================================================
|
||||
// DTO -> ENTITY Mappings (用于创建/更新) - 现在变得极其简单!
|
||||
// =================================================================
|
||||
CreateMap<AssignmentDto, Assignment>();
|
||||
CreateMap<AssignmentStructDto, AssignmentStruct>();
|
||||
|
||||
CreateMap<QuestionGroupDto, AssignmentGroup>()
|
||||
.ForMember(dest => dest.ChildAssignmentGroups, opt => opt.MapFrom(src => src.SubQuestionGroups))
|
||||
.ForMember(dest => dest.AssignmentQuestions, opt => opt.MapFrom(src => src.SubQuestions));
|
||||
// 新增!从新的 DTO 到实体的映射
|
||||
CreateMap<AssignmentQuestionDto, AssignmentQuestion>();
|
||||
|
||||
CreateMap<SubQuestionDto, AssignmentQuestion>()
|
||||
.ForMember(dest => dest.Question, opt => opt.MapFrom(src => src)); // 映射到嵌套的 Question 对象
|
||||
CreateMap<QuestionDto, Question>();
|
||||
|
||||
CreateMap<QuestionGroupDto, QuestionGroup>()
|
||||
.ForMember(dest => dest.ChildQuestionGroups, opt => opt.MapFrom(src => src.SubQuestionGroups))
|
||||
.ForMember(dest => dest.Title, opt => opt.MapFrom(src => src.Title))
|
||||
.ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Descript));
|
||||
|
||||
|
||||
|
||||
CreateMap<Assignment, ExamDto>();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -29,10 +29,10 @@ namespace TechHelper.Context.Configuration
|
||||
.IsRequired()
|
||||
.HasColumnName("due_date");
|
||||
|
||||
builder.Property(a => a.TotalPoints)
|
||||
builder.Property(a => a.TotalQuestions)
|
||||
.HasColumnName("total_points");
|
||||
|
||||
builder.Property(a => a.CreatedBy)
|
||||
builder.Property(a => a.CreatorId)
|
||||
.HasColumnName("created_by");
|
||||
|
||||
builder.Property(a => a.CreatedAt)
|
||||
@@ -54,7 +54,7 @@ namespace TechHelper.Context.Configuration
|
||||
// 如果 User 有一个名为 AssignmentsCreated 的导航属性,应写为 .WithMany(u => u.AssignmentsCreated)
|
||||
builder.HasOne(a => a.Creator)
|
||||
.WithMany() // User 实体没有指向 Assignment 的导航属性 (或我们不知道)
|
||||
.HasForeignKey(a => a.CreatedBy)
|
||||
.HasForeignKey(a => a.CreatorId)
|
||||
.IsRequired(); // CreatedBy 是必填的,对应 [Required] 在外键属性上
|
||||
|
||||
// 关系: Assignment (一) 到 AssignmentClass (多)
|
||||
|
@@ -4,9 +4,9 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace TechHelper.Context.Configuration
|
||||
{
|
||||
public class AssignmentGroupConfiguration : IEntityTypeConfiguration<AssignmentGroup>
|
||||
public class AssignmentGroupConfiguration : IEntityTypeConfiguration<AssignmentStruct>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<AssignmentGroup> builder)
|
||||
public void Configure(EntityTypeBuilder<AssignmentStruct> builder)
|
||||
{
|
||||
// 1. 设置表名
|
||||
// 将此实体映射到数据库中名为 "assignment_detail" 的表。
|
||||
@@ -34,23 +34,23 @@ namespace TechHelper.Context.Configuration
|
||||
.HasMaxLength(65535); // 对应 MaxLength(65535)
|
||||
|
||||
// 配置 Descript 属性对应的数据库列名为 "descript",并设置最大长度。
|
||||
builder.Property(ag => ag.Descript)
|
||||
builder.Property(ag => ag.Description)
|
||||
.HasColumnName("descript")
|
||||
.HasMaxLength(65535); // 对应 MaxLength(65535)
|
||||
|
||||
// 配置 TotalPoints 属性对应的数据库列名为 "total_points"。
|
||||
// TotalPoints 是 decimal? 类型,默认就是可选的,无需 IsRequired(false)。
|
||||
builder.Property(ag => ag.TotalPoints)
|
||||
builder.Property(ag => ag.Score)
|
||||
.HasColumnName("total_points");
|
||||
|
||||
// 配置 Number 属性对应的数据库列名为 "number"。
|
||||
builder.Property(ag => ag.Number)
|
||||
builder.Property(ag => ag.Index)
|
||||
.HasColumnName("number")
|
||||
.IsRequired(); // byte 默认非空,显式 IsRequired 增加可读性。
|
||||
|
||||
// 配置 ParentGroup 属性对应的数据库列名为 "sub_group"。
|
||||
// ParentGroup 是 Guid? 类型,默认就是可选的,无需 IsRequired(false)。
|
||||
builder.Property(ag => ag.ParentGroup)
|
||||
builder.Property(ag => ag.ParentStructId)
|
||||
.HasColumnName("parent_group")
|
||||
.IsRequired(false);
|
||||
|
||||
@@ -64,16 +64,16 @@ namespace TechHelper.Context.Configuration
|
||||
// 配置 AssignmentGroup 到 Assignment 的多对一关系。
|
||||
// 一个 AssignmentGroup 记录属于一个 Assignment。
|
||||
builder.HasOne(ag => ag.Assignment) // 当前 AssignmentGroup 有一个 Assignment
|
||||
.WithMany(a => a.AssignmentGroups) // 该 Assignment 可以有多个 AssignmentGroup 记录
|
||||
.HasForeignKey(ag => ag.AssignmentId) // 通过 AssignmentId 建立外键
|
||||
.OnDelete(DeleteBehavior.Cascade); // 当关联的 Assignment 被删除时,其所有相关的 AssignmentGroup 记录也级联删除。
|
||||
.WithOne(a => a.ExamStruct) // 该 Assignment 可以有多个 AssignmentGroup 记录
|
||||
.HasForeignKey<AssignmentStruct>(ag => ag.AssignmentId); // 通过 AssignmentId 建立外键
|
||||
|
||||
|
||||
// 配置 AssignmentGroup 到 AssignmentGroup 的自引用关系(父子关系)。
|
||||
// 一个 AssignmentGroup 可以有一个父 AssignmentGroup (SubAssignmentGroup)。
|
||||
// 假设父 AssignmentGroup 实体中有一个名为 ChildAssignmentGroups 的集合属性来表示它所包含的所有子组。
|
||||
builder.HasOne(ag => ag.ParentAssignmentGroup) // 当前 AssignmentGroup 有一个父 AssignmentGroup
|
||||
.WithMany(parentAg => parentAg.ChildAssignmentGroups) // 该父 AssignmentGroup 可以有多个子 AssignmentGroup
|
||||
.HasForeignKey(ag => ag.ParentGroup) // 通过 SubGroup 建立外键
|
||||
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。
|
||||
// 如果你希望父组被删除时子组不能脱离父组(即不允许父组被删除),
|
||||
|
@@ -25,12 +25,8 @@ namespace TechHelper.Context.Configuration
|
||||
.HasColumnName("question_id");
|
||||
|
||||
|
||||
builder.Property(aq => aq.QuestionGroupId)
|
||||
.HasColumnName("question_group_id");
|
||||
|
||||
|
||||
// 配置 QuestionNumber 列
|
||||
builder.Property(aq => aq.QuestionNumber)
|
||||
builder.Property(aq => aq.Index)
|
||||
.HasColumnName("question_number")
|
||||
.IsRequired(); // uint 类型默认非空
|
||||
|
||||
@@ -44,15 +40,10 @@ namespace TechHelper.Context.Configuration
|
||||
|
||||
// 配置 AssignmentGroupId 列
|
||||
// 该列在数据库中名为 "detail_id"
|
||||
builder.Property(aq => aq.AssignmentGroupId)
|
||||
builder.Property(aq => aq.AssignmentStructId)
|
||||
.HasColumnName("group_id")
|
||||
.IsRequired();
|
||||
|
||||
|
||||
builder.Property(aq => aq.IsGroup)
|
||||
.HasColumnName("is_group") // 修正为一致的列名
|
||||
.IsRequired(); // IsGroup 应该是必需的
|
||||
// 配置 IsDeleted 列
|
||||
builder.Property(aq => aq.IsDeleted)
|
||||
.HasColumnName("deleted")
|
||||
.HasDefaultValue(false); // 适用于软删除策略
|
||||
@@ -69,12 +60,6 @@ namespace TechHelper.Context.Configuration
|
||||
.HasForeignKey(aq => aq.QuestionId) // 外键是 AssignmentQuestion.QuestionId
|
||||
.OnDelete(DeleteBehavior.Cascade); // 当 Question 被删除时,相关的 AssignmentQuestion 也级联删除。
|
||||
|
||||
builder.HasOne(aq => aq.QuestionGroup)
|
||||
.WithMany(qg => qg.AssignmentQuestions)
|
||||
.HasForeignKey(aq => aq.QuestionGroupId)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
|
||||
// ---
|
||||
// 配置 AssignmentQuestion 到 AssignmentGroup 的关系 (多对一)
|
||||
// 一个 AssignmentQuestion 属于一个 AssignmentGroup。
|
||||
@@ -82,9 +67,9 @@ namespace TechHelper.Context.Configuration
|
||||
// 你的 `AssignmentQuestion` 类现在有了 `public AssignmentGroup AssignmentGroup { get; set; }`
|
||||
// 这是一个非常好的改进,它与 `AssignmentGroupId` 外键完美匹配。
|
||||
// 假设 `AssignmentGroup` 实体中有一个名为 `AssignmentQuestions` 的 `ICollection<AssignmentQuestion>` 集合属性。
|
||||
builder.HasOne(aq => aq.AssignmentGroup) // 当前 AssignmentQuestion 有一个 AssignmentGroup
|
||||
builder.HasOne(aq => aq.AssignmentStruct) // 当前 AssignmentQuestion 有一个 AssignmentGroup
|
||||
.WithMany(ag => ag.AssignmentQuestions) // 那个 AssignmentGroup 可以有多个 AssignmentQuestion
|
||||
.HasForeignKey(aq => aq.AssignmentGroupId) // 外键是 AssignmentQuestion.AssignmentGroupId (列名 detail_id)
|
||||
.HasForeignKey(aq => aq.AssignmentStructId) // 外键是 AssignmentQuestion.AssignmentGroupId (列名 detail_id)
|
||||
.OnDelete(DeleteBehavior.Cascade); // 当 AssignmentGroup 被删除时,相关的 AssignmentQuestion 也级联删除。
|
||||
|
||||
// ---
|
||||
|
@@ -0,0 +1,17 @@
|
||||
using Entities.Contracts;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace TechHelper.Context.Configuration
|
||||
{
|
||||
public class KeyPointConfiguration : IEntityTypeConfiguration<KeyPoint>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<KeyPoint> builder)
|
||||
{
|
||||
builder.HasOne(kp=>kp.Lesson)
|
||||
.WithMany(l => l.KeyPoints)
|
||||
.HasForeignKey(kp => kp.LessonID)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
@@ -14,7 +14,8 @@ namespace TechHelper.Context.Configuration
|
||||
// 2. 设置主键
|
||||
builder.HasKey(q => q.Id);
|
||||
|
||||
builder.HasIndex(q => q.QuestionText);
|
||||
builder.HasIndex(q => q.Title)
|
||||
.HasPrefixLength(20);
|
||||
|
||||
// 3. 配置列名、必需性、长度及其他属性
|
||||
|
||||
@@ -23,44 +24,37 @@ namespace TechHelper.Context.Configuration
|
||||
.HasColumnName("id");
|
||||
// 对于 Guid 类型的主键,EF Core 默认由应用程序生成值,无需 ValueGeneratedOnAdd()
|
||||
|
||||
builder.Property(q => q.QuestionGroupId)
|
||||
.HasColumnName("question_group_id")
|
||||
.IsRequired(false); // 可为空,因为题目不一定属于某个题组
|
||||
|
||||
|
||||
// QuestionText
|
||||
builder.Property(q => q.QuestionText)
|
||||
builder.Property(q => q.Title)
|
||||
.HasColumnName("question_text")
|
||||
.IsRequired()
|
||||
.HasMaxLength(65535); // 对应 MaxLength(65535)
|
||||
|
||||
// QuestionType (枚举作为字符串存储)
|
||||
builder.Property(q => q.QuestionType)
|
||||
builder.Property(q => q.Type)
|
||||
.HasColumnName("question_type")
|
||||
.IsRequired()
|
||||
.HasConversion<string>() // <-- 重要:将枚举存储为字符串
|
||||
.HasMaxLength(20); // <-- 应用最大长度
|
||||
.HasMaxLength(20);
|
||||
|
||||
// CorrectAnswer
|
||||
builder.Property(q => q.CorrectAnswer)
|
||||
builder.Property(q => q.Answer)
|
||||
.HasColumnName("correct_answer")
|
||||
.HasMaxLength(65535); // 对应 MaxLength(65535)
|
||||
.HasMaxLength(65535);
|
||||
|
||||
// DifficultyLevel (枚举作为字符串存储)
|
||||
builder.Property(q => q.DifficultyLevel)
|
||||
.HasColumnName("difficulty_level")
|
||||
.HasConversion<string>() // <-- 重要:将枚举存储为字符串
|
||||
.HasMaxLength(10); // <-- 应用最大长度
|
||||
// DifficultyLevel 属性没有 [Required],所以默认是可选的
|
||||
.HasMaxLength(10);
|
||||
|
||||
|
||||
// SubjectArea
|
||||
builder.Property(q => q.SubjectArea)
|
||||
.HasColumnName("subject_area")
|
||||
.HasConversion<string>() // <--- 重要:将枚举存储为字符串
|
||||
.HasMaxLength(100); // <--- 应用最大长度 (从原 StringLength 继承)
|
||||
.HasMaxLength(100);
|
||||
|
||||
// CreatedBy
|
||||
builder.Property(q => q.CreatedBy)
|
||||
builder.Property(q => q.CreatorId)
|
||||
.HasColumnName("created_by")
|
||||
.IsRequired();
|
||||
|
||||
@@ -91,7 +85,7 @@ namespace TechHelper.Context.Configuration
|
||||
// 假设 `User` 实体中有一个名为 `CreatedQuestions` 的 `ICollection<Question>` 集合属性。
|
||||
builder.HasOne(q => q.Creator) // 当前 Question 有一个 Creator
|
||||
.WithMany(u => u.CreatedQuestions) // 那个 Creator 可以创建多个 Question
|
||||
.HasForeignKey(q => q.CreatedBy) // 外键是 Question.CreatedBy
|
||||
.HasForeignKey(q => q.CreatorId) // 外键是 Question.CreatedBy
|
||||
.OnDelete(DeleteBehavior.Restrict); // 当 User (Creator) 被删除时,如果还有他/她创建的 Question,则会阻止删除。
|
||||
// 由于 CreatedBy 是 [Required],Prevent/Restrict 是一个安全的选择。
|
||||
|
||||
@@ -105,11 +99,24 @@ namespace TechHelper.Context.Configuration
|
||||
.WithOne(aq => aq.Question); // 每一个 AssignmentQuestion 都有一个 Question
|
||||
// .HasForeignKey(aq => aq.QuestionId); // 外键的配置应在 `AssignmentQuestionConfiguration` 中进行
|
||||
|
||||
builder.HasOne(q => q.QuestionGroup) // Question 实体中的 QuestionGroup 导航属性
|
||||
.WithMany(qg => qg.Questions) // QuestionGroup 实体中的 Questions 集合
|
||||
.HasForeignKey(q => q.QuestionGroupId) // Question 实体中的 QuestionGroupId 外键
|
||||
.IsRequired(false) // QuestionGroupId 在 Question 实体中是可空的
|
||||
.OnDelete(DeleteBehavior.SetNull); // 如果 QuestionGroup 被删除,关联的 Question 的外键设置为 NULL
|
||||
|
||||
builder.HasOne(q => q.KeyPoint)
|
||||
.WithMany(kp => kp.Questions)
|
||||
.HasForeignKey(q => q.KeyPointId)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
builder.HasOne(q => q.Lesson)
|
||||
.WithMany(kp => kp.Questions)
|
||||
.IsRequired(false)
|
||||
.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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,111 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Entities.Contracts;
|
||||
|
||||
namespace TechHelper.Server.Context.Configuration
|
||||
{
|
||||
public class QuestionGroupConfiguration : IEntityTypeConfiguration<QuestionGroup>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<QuestionGroup> builder)
|
||||
{
|
||||
// 1. 设置表名
|
||||
builder.ToTable("question_groups");
|
||||
|
||||
// 2. 设置主键
|
||||
builder.HasKey(qg => qg.Id);
|
||||
|
||||
// 3. 配置列属性
|
||||
|
||||
// Title 标题
|
||||
builder.Property(qg => qg.Title)
|
||||
.HasColumnName("title")
|
||||
.HasMaxLength(255)
|
||||
.IsRequired(false); // 允许为空
|
||||
|
||||
// Description 描述内容 (Required)
|
||||
builder.Property(qg => qg.Description)
|
||||
.HasColumnName("description")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext"); // 对应 MySQL 的 TEXT 或 LONGTEXT
|
||||
|
||||
// Type 类型 (例如: "ReadingComprehension", "DiagramAnalysis")
|
||||
builder.Property(qg => qg.Type)
|
||||
.HasColumnName("type")
|
||||
.HasMaxLength(50)
|
||||
.IsRequired(false); // 允许为空
|
||||
|
||||
// DifficultyLevel 难度级别 (枚举映射为字符串)
|
||||
builder.Property(qg => qg.DifficultyLevel)
|
||||
.HasColumnName("difficulty_level")
|
||||
.HasConversion<string>() // 将枚举转换为字符串存储
|
||||
.HasMaxLength(10);
|
||||
|
||||
// SubjectArea 科目领域 (枚举映射为字符串)
|
||||
builder.Property(qg => qg.SubjectArea)
|
||||
.HasColumnName("subject_area")
|
||||
.HasConversion<string>(); // 将枚举转换为字符串存储
|
||||
|
||||
// TotalQuestions 包含题目总数
|
||||
builder.Property(qg => qg.TotalQuestions)
|
||||
.HasColumnName("total_questions")
|
||||
.IsRequired();
|
||||
|
||||
// ParentQG 父题组 ID (外键,自引用关系)
|
||||
builder.Property(qg => qg.ParentQG)
|
||||
.HasColumnName("parent_question_group") // 使用你定义的列名
|
||||
.IsRequired(false); // 可为空,因为根题组没有父级
|
||||
|
||||
// CreatedBy 创建者 ID (外键)
|
||||
builder.Property(qg => qg.CreatedBy)
|
||||
.HasColumnName("created_by")
|
||||
.IsRequired();
|
||||
|
||||
// CreatedAt 创建时间
|
||||
builder.Property(qg => qg.CreatedAt)
|
||||
.HasColumnName("created_at")
|
||||
.IsRequired();
|
||||
|
||||
// UpdatedAt 更新时间
|
||||
builder.Property(qg => qg.UpdatedAt)
|
||||
.HasColumnName("updated_at")
|
||||
.IsRequired();
|
||||
|
||||
// IsDeleted 是否删除 (软删除)
|
||||
builder.Property(qg => qg.IsDeleted)
|
||||
.HasColumnName("deleted")
|
||||
.IsRequired();
|
||||
|
||||
// ValidGroup 是否有效
|
||||
builder.Property(qg => qg.ValidGroup)
|
||||
.HasColumnName("valid_group")
|
||||
.IsRequired();
|
||||
|
||||
// 4. 配置关系
|
||||
|
||||
// 与 User 的关系 (创建者)
|
||||
builder.HasOne(qg => qg.Creator)
|
||||
.WithMany()
|
||||
.HasForeignKey(qg => qg.CreatedBy)
|
||||
.OnDelete(DeleteBehavior.Restrict); // 阻止删除关联的 User
|
||||
|
||||
// 与 Question 的关系 (一对多)
|
||||
// 一个 QuestionGroup 可以包含多个 Question
|
||||
builder.HasMany(qg => qg.Questions)
|
||||
.WithOne(q => q.QuestionGroup) // Question 实体中的 QuestionGroup 导航属性
|
||||
.HasForeignKey(q => q.QuestionGroupId) // Question 实体中的 QuestionGroupId 外键
|
||||
.IsRequired(false) // QuestionGroupId 在 Question 实体中是可空的
|
||||
.OnDelete(DeleteBehavior.SetNull); // 如果 QuestionGroup 被删除,关联的 Question 的外键设置为 NULL
|
||||
|
||||
// 与自身的自引用关系 (父子题组)
|
||||
// 一个 QuestionGroup 可以有多个 ChildQuestionGroups
|
||||
builder.HasMany(qg => qg.ChildQuestionGroups)
|
||||
.WithOne(childQG => childQG.ParentQuestionGroup) // 子 QuestionGroup 实体中的 ParentQuestionGroup 导航属性
|
||||
.HasForeignKey(childQG => childQG.ParentQG) // 子 QuestionGroup 实体中的 ParentQG 外键
|
||||
.IsRequired(false) // ParentQG 是可空的,因为根题组没有父级
|
||||
.OnDelete(DeleteBehavior.Restrict); // 或者 SetNull, Cascade。Restrict 更安全,避免意外删除整个分支。
|
||||
// 如果选择 SetNull,删除父组时子组的 ParentQG 会变为 NULL,它们就成了新的根组。
|
||||
// 如果选择 Cascade,删除父组会递归删除所有子组。根据业务逻辑选择。
|
||||
// 这里我选择了 Restrict 作为默认安全选项。
|
||||
}
|
||||
}
|
||||
}
|
@@ -30,18 +30,13 @@ namespace TechHelper.Context.Configuration
|
||||
.HasColumnName("student_id")
|
||||
.IsRequired();
|
||||
|
||||
// AttemptNumber
|
||||
// 注意:如果 AttemptNumber 应该是一个递增的数字,Guid 可能不是最合适的类型。
|
||||
// 但根据你的定义,这里按 Guid 类型配置。
|
||||
builder.Property(s => s.AttemptNumber)
|
||||
.HasColumnName("attempt_number")
|
||||
.IsRequired();
|
||||
|
||||
// SubmissionTime
|
||||
builder.Property(s => s.SubmissionTime)
|
||||
.HasColumnName("submission_time"); // 没有 [Required] 属性,所以可以是可空的
|
||||
|
||||
// OverallGrade
|
||||
builder.Property(s => s.OverallGrade)
|
||||
.HasColumnName("overall_grade")
|
||||
.HasPrecision(5, 2); // 应用精度设置
|
||||
@@ -51,59 +46,45 @@ namespace TechHelper.Context.Configuration
|
||||
.HasColumnName("overall_feedback");
|
||||
|
||||
// GradedBy (现为 Guid? 类型)
|
||||
builder.Property(s => s.GradedBy)
|
||||
.HasColumnName("graded_by"); // 作为可空外键,不需要 IsRequired()
|
||||
builder.Property(s => s.GraderId)
|
||||
.HasColumnName("graded_by");
|
||||
|
||||
|
||||
// GradedAt
|
||||
builder.Property(s => s.GradedAt)
|
||||
.HasColumnName("graded_at");
|
||||
|
||||
// IsDeleted
|
||||
|
||||
builder.Property(s => s.IsDeleted)
|
||||
.HasColumnName("deleted")
|
||||
.HasDefaultValue(false);
|
||||
|
||||
// Status (枚举作为字符串存储)
|
||||
builder.Property(s => s.Status)
|
||||
.HasColumnName("status")
|
||||
.IsRequired()
|
||||
.HasConversion<string>() // <--- 重要:将枚举存储为字符串
|
||||
.HasMaxLength(15); // <--- 应用最大长度
|
||||
.HasMaxLength(15);
|
||||
|
||||
|
||||
|
||||
// 4. 配置导航属性和外键关系
|
||||
|
||||
// ---
|
||||
// 配置 Submission 到 Assignment 的关系 (多对一)
|
||||
// 一个 Submission 属于一个 Assignment。
|
||||
builder.HasOne(s => s.Assignment) // 当前 Submission 有一个 Assignment
|
||||
.WithMany(a => a.Submissions) // 那个 Assignment 可以有多个 Submission
|
||||
.HasForeignKey(s => s.AssignmentId) // 外键是 Submission.AssignmentId
|
||||
.OnDelete(DeleteBehavior.Cascade); // 当 Assignment 被删除时,相关的 Submission 也级联删除。
|
||||
|
||||
// ---
|
||||
// 配置 Submission 到 User (Student) 的关系 (多对一)
|
||||
// 一个 Submission 由一个 User (Student) 提交。
|
||||
|
||||
builder.HasOne(s => s.Student) // 当前 Submission 有一个 Student (User)
|
||||
.WithMany(u => u.SubmissionsAsStudent) // 那个 User (Student) 可以有多个 Submission
|
||||
.HasForeignKey(s => s.StudentId) // 外键是 Submission.StudentId
|
||||
.OnDelete(DeleteBehavior.Restrict); // 当 User (Student) 被删除时,如果还有其提交的 Submission,则会阻止删除。
|
||||
|
||||
// ---
|
||||
// 配置 Submission 到 User (Grader) 的关系 (多对一)
|
||||
// 一个 Submission 可以由一个 User (Grader) 批改 (可选)。
|
||||
builder.HasOne(s => s.Grader) // 当前 Submission 有一个 Grader (User),可以是空的
|
||||
.WithMany(u => u.GradedSubmissions) // 那个 User (Grader) 可以批改多个 Submission
|
||||
.HasForeignKey(s => s.GradedBy) // 外键是 Submission.GradedBy
|
||||
.HasForeignKey(s => s.GraderId) // 外键是 Submission.GradedBy
|
||||
.OnDelete(DeleteBehavior.SetNull); // 当 User (Grader) 被删除时,如果 GradedBy 是可空的,则将其设置为 NULL。
|
||||
// 如果 GradedBy 是不可空的,需要改为 Restrict 或 Cascade。
|
||||
|
||||
// ---
|
||||
// 配置 Submission 到 SubmissionDetail 的关系 (一对多)
|
||||
// 一个 Submission 可以有多个 SubmissionDetail。
|
||||
// 这个关系的外键配置通常在 "多" 的一方 (`SubmissionDetail` 实体) 进行。
|
||||
|
||||
builder.HasMany(s => s.SubmissionDetails) // 当前 Submission 有多个 SubmissionDetail
|
||||
.WithOne(sd => sd.Submission); // 每一个 SubmissionDetail 都有一个 Submission
|
||||
// .HasForeignKey(sd => sd.SubmissionId); // 外键的配置应在 `SubmissionDetailConfiguration` 中进行
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,94 +8,65 @@ namespace TechHelper.Context.Configuration
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<SubmissionDetail> builder)
|
||||
{
|
||||
// 1. 设置表名
|
||||
// 将此实体映射到数据库中名为 "submission_details" 的表。
|
||||
builder.ToTable("submission_details");
|
||||
|
||||
// 2. 设置主键
|
||||
// 将 Id 属性设置为主键。
|
||||
builder.HasKey(sd => sd.Id);
|
||||
|
||||
// 3. 配置列名、必需性、精度及其他属性
|
||||
|
||||
// Id 属性对应的数据库列名为 "id"。
|
||||
builder.Property(sd => sd.Id)
|
||||
.HasColumnName("id");
|
||||
|
||||
// SubmissionId 属性对应的数据库列名为 "submission_id",并设置为必需字段。
|
||||
builder.Property(sd => sd.SubmissionId)
|
||||
.HasColumnName("submission_id")
|
||||
.IsRequired();
|
||||
|
||||
// StudentId 属性对应的数据库列名为 "student_id",并设置为必需字段。
|
||||
// 此外键指向 User 实体,代表提交该详情的学生。
|
||||
builder.Property(sd => sd.StudentId)
|
||||
.HasColumnName("student_id")
|
||||
.IsRequired();
|
||||
|
||||
// AssignmentQuestionId 属性对应的数据库列名为 "assignment_question_id",并设置为必需字段。
|
||||
builder.Property(sd => sd.AssignmentQuestionId)
|
||||
.HasColumnName("assignment_question_id")
|
||||
.IsRequired();
|
||||
|
||||
// StudentAnswer 属性对应的数据库列名为 "student_answer"。
|
||||
builder.Property(sd => sd.StudentAnswer)
|
||||
.HasColumnName("student_answer"); // string 默认可空
|
||||
|
||||
// IsCorrect 属性对应的数据库列名为 "is_correct"。
|
||||
builder.Property(sd => sd.IsCorrect)
|
||||
.HasColumnName("is_correct"); // bool? 默认可空
|
||||
|
||||
// PointsAwarded 属性对应的数据库列名为 "points_awarded",并设置精度。
|
||||
builder.Property(sd => sd.PointsAwarded)
|
||||
.HasColumnName("points_awarded")
|
||||
.HasPrecision(5, 2); // 应用 [Precision(5, 2)] 设置
|
||||
|
||||
// TeacherFeedback 属性对应的数据库列名为 "teacher_feedback"。
|
||||
builder.Property(sd => sd.TeacherFeedback)
|
||||
.HasColumnName("teacher_feedback"); // string 默认可空
|
||||
|
||||
// CreatedAt 属性对应的数据库列名为 "created_at",设置为必需字段,并在添加时自动生成值。
|
||||
builder.Property(sd => sd.CreatedAt)
|
||||
.HasColumnName("created_at")
|
||||
.IsRequired()
|
||||
.ValueGeneratedOnAdd(); // 在实体首次保存时自动设置值
|
||||
|
||||
// UpdatedAt 属性对应的数据库列名为 "updated_at",设置为必需字段,并在添加或更新时自动生成值,同时作为并发令牌。
|
||||
builder.Property(sd => sd.UpdatedAt)
|
||||
.HasColumnName("updated_at")
|
||||
.IsRequired()
|
||||
.ValueGeneratedOnAddOrUpdate() // 在实体添加或更新时自动设置值
|
||||
.IsConcurrencyToken(); // 用作乐观并发控制,防止同时修改同一记录
|
||||
|
||||
// IsDeleted 属性对应的数据库列名为 "deleted",并设置默认值为 false。
|
||||
|
||||
builder.Property(sd => sd.IsDeleted)
|
||||
.HasColumnName("deleted")
|
||||
.HasDefaultValue(false); // 常用作软删除标记
|
||||
.HasDefaultValue(false);
|
||||
|
||||
// 4. 配置导航属性和外键关系
|
||||
|
||||
// ---
|
||||
// 配置 SubmissionDetail 到 Submission 的关系 (多对一)
|
||||
// 一个 SubmissionDetail 记录属于一个 Submission。
|
||||
builder.HasOne(sd => sd.Submission) // 当前 SubmissionDetail 有一个 Submission
|
||||
.WithMany(s => s.SubmissionDetails) // 那个 Submission 可以有多个 SubmissionDetail 记录
|
||||
.HasForeignKey(sd => sd.SubmissionId) // 外键是 SubmissionDetail.SubmissionId
|
||||
.OnDelete(DeleteBehavior.Cascade); // 当 Submission 被删除时,相关的 SubmissionDetail 记录也级联删除。
|
||||
|
||||
// ---
|
||||
// 配置 SubmissionDetail 到 User (作为 Student) 的关系 (多对一)
|
||||
// 一个 SubmissionDetail 记录与一个 User (提交该详情的学生) 相关联。
|
||||
// 假设 `User` 实体中有一个名为 `SubmissionDetailsAsStudent` 的 `ICollection<SubmissionDetail>` 集合属性。
|
||||
builder.HasOne(sd => sd.User) // 当前 SubmissionDetail 有一个 User (作为学生)
|
||||
builder.HasOne(sd => sd.Student) // 当前 SubmissionDetail 有一个 User (作为学生)
|
||||
.WithMany(u => u.SubmissionDetails)
|
||||
.HasForeignKey(sd => sd.StudentId) // 外键是 SubmissionDetail.StudentId
|
||||
.OnDelete(DeleteBehavior.Restrict); // 当 User (学生) 被删除时,如果他/她还有提交详情,则会阻止删除。
|
||||
// 这是一个更安全的选择,以防止意外数据丢失。
|
||||
|
||||
// ---
|
||||
// 配置 SubmissionDetail 到 AssignmentQuestion 的关系 (多对一)
|
||||
// 一个 SubmissionDetail 记录对应一个 AssignmentQuestion。
|
||||
builder.HasOne(sd => sd.AssignmentQuestion) // 当前 SubmissionDetail 有一个 AssignmentQuestion
|
||||
.WithMany(aq => aq.SubmissionDetails) // 那个 AssignmentQuestion 可以有多个 SubmissionDetail 记录
|
||||
.HasForeignKey(sd => sd.AssignmentQuestionId) // 外键是 SubmissionDetail.AssignmentQuestionId
|
||||
|
@@ -8,14 +8,8 @@ namespace TechHelper.Context.Configuration
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<User> builder)
|
||||
{
|
||||
// 映射到表名:如果 User 类上没有 [Table("users")],默认是 "AspNetUsers"。
|
||||
// 显式指定可以确保你的数据库表名和你期望的一致。
|
||||
builder.ToTable("AspNetUsers");
|
||||
|
||||
// IdentityUser 的 Id 属性和其他标准属性(如 UserName, Email 等)
|
||||
// 大多由 IdentityDbContext 自动处理,通常不需要在这里显式配置主键或默认列。
|
||||
|
||||
// 配置自定义属性
|
||||
builder.Property(u => u.RefreshToken)
|
||||
.HasColumnName("refresh_token");
|
||||
|
||||
@@ -24,11 +18,8 @@ namespace TechHelper.Context.Configuration
|
||||
|
||||
builder.Property(u => u.IsDeleted)
|
||||
.HasColumnName("deleted")
|
||||
.HasDefaultValue(false); // 软删除标记,默认 false
|
||||
.HasDefaultValue(false);
|
||||
|
||||
// 配置导航属性 (User 作为关系的“一”或“主”方)
|
||||
|
||||
// User 作为老师,与 ClassTeacher 的关系 (一对多)
|
||||
builder.HasMany(u => u.TaughtClassesLink) // 一个 User (老师) 可以教授多个班级
|
||||
.WithOne(ct => ct.Teacher) // 一个 ClassTeacher 记录对应一个 Teacher
|
||||
.HasForeignKey(ct => ct.TeacherId) // 外键在 ClassTeacher.TeacherId
|
||||
@@ -43,20 +34,17 @@ namespace TechHelper.Context.Configuration
|
||||
// User 作为创建者,与 Question 的关系 (一对多)
|
||||
builder.HasMany(u => u.CreatedQuestions) // 一个 User 可以创建多个题目
|
||||
.WithOne(q => q.Creator) // 一个 Question 对应一个 Creator
|
||||
.HasForeignKey(q => q.CreatedBy) // 外键在 Question.CreatedBy
|
||||
.HasForeignKey(q => q.CreatorId) // 外键在 Question.CreatedBy
|
||||
.OnDelete(DeleteBehavior.Restrict); // 限制删除:如果创建者有题目,则不允许删除
|
||||
|
||||
// User 作为创建者,与 Assignment 的关系 (一对多)
|
||||
builder.HasMany(u => u.CreatedAssignments) // 一个 User 可以创建多个作业
|
||||
.WithOne(a => a.Creator) // 一个 Assignment 对应一个 Creator
|
||||
.HasForeignKey(a => a.CreatedBy) // 外键在 Assignment.CreatedBy
|
||||
.HasForeignKey(a => a.CreatorId) // 外键在 Assignment.CreatedBy
|
||||
.OnDelete(DeleteBehavior.Restrict); // 限制删除:如果创建者有作业,则不允许删除
|
||||
|
||||
// User 作为学生,与 SubmissionDetail 的关系 (一对多)
|
||||
// 尽管 SubmissionDetail 也可以通过 Submission 间接关联到 User,
|
||||
// 但这里提供了直接访问的导航属性,以方便直接查询学生的所有作答详情。
|
||||
builder.HasMany(u => u.SubmissionDetails) // 一个 User (学生) 可以有多个提交详情记录
|
||||
.WithOne(sd => sd.User) // 一个 SubmissionDetail 对应一个 User (学生)
|
||||
.WithOne(sd => sd.Student) // 一个 SubmissionDetail 对应一个 User (学生)
|
||||
.HasForeignKey(sd => sd.StudentId) // 外键在 SubmissionDetail.StudentId
|
||||
.OnDelete(DeleteBehavior.Restrict); // 限制删除:如果学生有提交详情,则不允许删除
|
||||
|
||||
@@ -69,7 +57,7 @@ namespace TechHelper.Context.Configuration
|
||||
// User 作为批改者,与 Submission 的关系 (一对多)
|
||||
builder.HasMany(u => u.GradedSubmissions) // 一个 User (批改者) 可以批改多个提交
|
||||
.WithOne(s => s.Grader) // 一个 Submission 对应一个 Grader
|
||||
.HasForeignKey(s => s.GradedBy) // 外键在 Submission.GradedBy
|
||||
.HasForeignKey(s => s.GraderId) // 外键在 Submission.GradedBy
|
||||
.OnDelete(DeleteBehavior.SetNull); // 因为 GradedBy 是可空的,所以批改者删除时,设为 NULL
|
||||
}
|
||||
}
|
||||
|
@@ -28,9 +28,13 @@ namespace TechHelper.Server.Controllers
|
||||
|
||||
[HttpPost("add")]
|
||||
public async Task<IActionResult> AddExam(
|
||||
[FromBody] ExamDto examDto)
|
||||
[FromBody] AssignmentDto examDto)
|
||||
{
|
||||
var result = await _examService.AddAsync(examDto);
|
||||
var user = await _userManager.FindByEmailAsync(User.Identity?.Name ?? "");
|
||||
if(user == null) return BadRequest("无效的用户");
|
||||
|
||||
examDto.CreatorId = user.Id;
|
||||
var result = await _examService.CreateExamAsync(examDto);
|
||||
if (result.Status)
|
||||
{
|
||||
return Ok(result);
|
||||
@@ -63,7 +67,7 @@ namespace TechHelper.Server.Controllers
|
||||
|
||||
|
||||
|
||||
var result = await _examService.GetAllExamPreview(userid.Id);
|
||||
var result = await _examService.GetAllExamPreviewsAsync(userid.Id);
|
||||
|
||||
if (result.Status)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,93 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||
|
||||
namespace TechHelper.Server.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class assignmentnot_required : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("02a808ba-bd16-4f90-bf2b-0bc42f767e00"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("9e526681-e57e-46b5-a01c-5731b27bfc4a"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("dfdfb884-4063-4161-84e0-9c225f4e883c"));
|
||||
|
||||
migrationBuilder.AlterColumn<Guid>(
|
||||
name: "assignment",
|
||||
table: "assignment_group",
|
||||
type: "char(36)",
|
||||
nullable: true,
|
||||
collation: "ascii_general_ci",
|
||||
oldClrType: typeof(Guid),
|
||||
oldType: "char(36)")
|
||||
.OldAnnotation("Relational:Collation", "ascii_general_ci");
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("b2e087e6-ea32-46c4-aeb3-09b936cd0cf4"), null, "Teacher", "TEACHER" },
|
||||
{ new Guid("ba33e047-8354-4f2c-b8b1-1f46441c28fc"), null, "Administrator", "ADMINISTRATOR" },
|
||||
{ new Guid("d4b41bc3-612e-49dd-aeda-6a98ea0e4e68"), null, "Student", "STUDENT" }
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("b2e087e6-ea32-46c4-aeb3-09b936cd0cf4"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("ba33e047-8354-4f2c-b8b1-1f46441c28fc"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "AspNetRoles",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("d4b41bc3-612e-49dd-aeda-6a98ea0e4e68"));
|
||||
|
||||
migrationBuilder.AlterColumn<Guid>(
|
||||
name: "assignment",
|
||||
table: "assignment_group",
|
||||
type: "char(36)",
|
||||
nullable: false,
|
||||
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
|
||||
collation: "ascii_general_ci",
|
||||
oldClrType: typeof(Guid),
|
||||
oldType: "char(36)",
|
||||
oldNullable: true)
|
||||
.OldAnnotation("Relational:Collation", "ascii_general_ci");
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "AspNetRoles",
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("02a808ba-bd16-4f90-bf2b-0bc42f767e00"), null, "Administrator", "ADMINISTRATOR" },
|
||||
{ new Guid("9e526681-e57e-46b5-a01c-5731b27bfc4a"), null, "Student", "STUDENT" },
|
||||
{ new Guid("dfdfb884-4063-4161-84e0-9c225f4e883c"), null, "Teacher", "TEACHER" }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,7 +12,7 @@ using TechHelper.Context;
|
||||
namespace TechHelper.Server.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationContext))]
|
||||
[Migration("20250610025325_init")]
|
||||
[Migration("20250619070929_init")]
|
||||
partial class init
|
||||
{
|
||||
/// <inheritdoc />
|
||||
@@ -36,7 +36,7 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("datetime(6)")
|
||||
.HasColumnName("created_at");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
b.Property<Guid>("CreatorId")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("created_by");
|
||||
|
||||
@@ -53,9 +53,12 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("tinyint(1)")
|
||||
.HasColumnName("deleted");
|
||||
|
||||
b.Property<string>("SubjectArea")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext")
|
||||
b.Property<float>("Score")
|
||||
.HasColumnType("float")
|
||||
.HasColumnName("score");
|
||||
|
||||
b.Property<byte>("SubjectArea")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("subject_area");
|
||||
|
||||
b.Property<string>("Title")
|
||||
@@ -64,8 +67,8 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("varchar(255)")
|
||||
.HasColumnName("title");
|
||||
|
||||
b.Property<float?>("TotalPoints")
|
||||
.HasColumnType("float")
|
||||
b.Property<byte>("TotalQuestions")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("total_points");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
@@ -77,7 +80,7 @@ namespace TechHelper.Server.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedBy");
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
@@ -151,61 +154,6 @@ namespace TechHelper.Server.Migrations
|
||||
b.ToTable("assignment_class", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.AssignmentGroup", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<Guid?>("AssignmentId")
|
||||
.IsRequired()
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("assignment");
|
||||
|
||||
b.Property<string>("Descript")
|
||||
.IsRequired()
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("longtext")
|
||||
.HasColumnName("descript");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("tinyint(1)")
|
||||
.HasDefaultValue(false)
|
||||
.HasColumnName("deleted");
|
||||
|
||||
b.Property<byte>("Number")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("number");
|
||||
|
||||
b.Property<Guid?>("ParentGroup")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("parent_group");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("longtext")
|
||||
.HasColumnName("title");
|
||||
|
||||
b.Property<float?>("TotalPoints")
|
||||
.HasColumnType("float")
|
||||
.HasColumnName("total_points");
|
||||
|
||||
b.Property<bool>("ValidQuestionGroup")
|
||||
.HasColumnType("tinyint(1)")
|
||||
.HasColumnName("valid_question_group");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AssignmentId");
|
||||
|
||||
b.HasIndex("ParentGroup");
|
||||
|
||||
b.ToTable("assignment_group", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@@ -221,6 +169,10 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("datetime(6)")
|
||||
.HasColumnName("created_at");
|
||||
|
||||
b.Property<byte>("Index")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("question_number");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("tinyint(1)")
|
||||
@@ -231,10 +183,6 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("question_id");
|
||||
|
||||
b.Property<byte>("QuestionNumber")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("question_number");
|
||||
|
||||
b.Property<float?>("Score")
|
||||
.HasColumnType("float")
|
||||
.HasColumnName("score");
|
||||
@@ -248,6 +196,61 @@ namespace TechHelper.Server.Migrations
|
||||
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")
|
||||
.HasColumnName("number");
|
||||
|
||||
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")
|
||||
.IsRequired()
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("longtext")
|
||||
.HasColumnName("title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AssignmentId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("ParentGroupId");
|
||||
|
||||
b.ToTable("assignment_group", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Class", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@@ -337,9 +340,8 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("teacher_id");
|
||||
|
||||
b.Property<string>("SubjectTaught")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext")
|
||||
b.Property<byte>("SubjectTaught")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("subject_taught");
|
||||
|
||||
b.HasKey("ClassId", "TeacherId");
|
||||
@@ -349,6 +351,72 @@ namespace TechHelper.Server.Migrations
|
||||
b.ToTable("class_teachers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.KeyPoint", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("varchar(255)");
|
||||
|
||||
b.Property<Guid>("LessonID")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("LessonID");
|
||||
|
||||
b.ToTable("key_point");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Lesson", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<Guid>("TextbookID")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("varchar(255)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TextbookID");
|
||||
|
||||
b.ToTable("lesson");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.LessonQuestion", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<Guid>("LessonID")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<string>("Question")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("LessonID");
|
||||
|
||||
b.ToTable("lesson_question");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Question", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@@ -356,8 +424,7 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<string>("CorrectAnswer")
|
||||
.IsRequired()
|
||||
b.Property<string>("Answer")
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("longtext")
|
||||
.HasColumnName("correct_answer");
|
||||
@@ -369,53 +436,75 @@ namespace TechHelper.Server.Migrations
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<DateTime>("CreatedAt"));
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
b.Property<Guid>("CreatorId")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("created_by");
|
||||
|
||||
b.Property<string>("DifficultyLevel")
|
||||
.IsRequired()
|
||||
b.Property<byte>("DifficultyLevel")
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("varchar(10)")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("difficulty_level");
|
||||
|
||||
b.Property<byte>("GroupState")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("group_state");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("tinyint(1)")
|
||||
.HasDefaultValue(false)
|
||||
.HasColumnName("deleted");
|
||||
|
||||
b.Property<string>("QuestionText")
|
||||
b.Property<Guid?>("KeyPointId")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("key_point");
|
||||
|
||||
b.Property<Guid?>("LessonId")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("lesson");
|
||||
|
||||
b.Property<string>("Options")
|
||||
.HasColumnType("longtext")
|
||||
.HasColumnName("options");
|
||||
|
||||
b.Property<Guid?>("ParentQuestionId")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("parent_question_group_id");
|
||||
|
||||
b.Property<byte>("SubjectArea")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("subject_area");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("longtext")
|
||||
.HasColumnName("question_text");
|
||||
|
||||
b.Property<string>("QuestionType")
|
||||
.IsRequired()
|
||||
b.Property<byte>("Type")
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("varchar(20)")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("question_type");
|
||||
|
||||
b.Property<string>("SubjectArea")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("varchar(100)")
|
||||
.HasColumnName("subject_area");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("datetime(6)")
|
||||
.HasColumnName("updated_at");
|
||||
|
||||
b.Property<bool>("ValidQuestion")
|
||||
.HasColumnType("tinyint(1)")
|
||||
.HasColumnName("valid_question");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedBy");
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.HasIndex("KeyPointId");
|
||||
|
||||
b.HasIndex("LessonId");
|
||||
|
||||
b.HasIndex("ParentQuestionId");
|
||||
|
||||
b.HasIndex("Title")
|
||||
.HasAnnotation("MySql:IndexPrefixLength", new[] { 20 });
|
||||
|
||||
b.ToTable("questions", (string)null);
|
||||
});
|
||||
@@ -439,7 +528,7 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("datetime(6)")
|
||||
.HasColumnName("graded_at");
|
||||
|
||||
b.Property<Guid?>("GradedBy")
|
||||
b.Property<Guid?>("GraderId")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("graded_by");
|
||||
|
||||
@@ -459,10 +548,9 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("float")
|
||||
.HasColumnName("overall_grade");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
b.Property<int>("Status")
|
||||
.HasMaxLength(15)
|
||||
.HasColumnType("varchar(15)")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("status");
|
||||
|
||||
b.Property<Guid>("StudentId")
|
||||
@@ -477,7 +565,7 @@ namespace TechHelper.Server.Migrations
|
||||
|
||||
b.HasIndex("AssignmentId");
|
||||
|
||||
b.HasIndex("GradedBy");
|
||||
b.HasIndex("GraderId");
|
||||
|
||||
b.HasIndex("StudentId");
|
||||
|
||||
@@ -552,6 +640,30 @@ namespace TechHelper.Server.Migrations
|
||||
b.ToTable("submission_details", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Textbook", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<byte>("Grade")
|
||||
.HasColumnType("tinyint unsigned");
|
||||
|
||||
b.Property<byte>("Publisher")
|
||||
.HasColumnType("tinyint unsigned");
|
||||
|
||||
b.Property<byte>("SubjectArea")
|
||||
.HasColumnType("tinyint unsigned");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("textbook");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@@ -662,19 +774,19 @@ namespace TechHelper.Server.Migrations
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = new Guid("9e526681-e57e-46b5-a01c-5731b27bfc4a"),
|
||||
Id = new Guid("895d8f32-714e-4a14-bd97-8fa262b83172"),
|
||||
Name = "Student",
|
||||
NormalizedName = "STUDENT"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("dfdfb884-4063-4161-84e0-9c225f4e883c"),
|
||||
Id = new Guid("d182c396-c656-42da-965a-d93c17a1f74f"),
|
||||
Name = "Teacher",
|
||||
NormalizedName = "TEACHER"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("02a808ba-bd16-4f90-bf2b-0bc42f767e00"),
|
||||
Id = new Guid("4e65fab9-3315-4474-b92c-bdab5a617e65"),
|
||||
Name = "Administrator",
|
||||
NormalizedName = "ADMINISTRATOR"
|
||||
});
|
||||
@@ -787,7 +899,7 @@ namespace TechHelper.Server.Migrations
|
||||
{
|
||||
b.HasOne("Entities.Contracts.User", "Creator")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedBy")
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
@@ -828,27 +940,9 @@ namespace TechHelper.Server.Migrations
|
||||
b.Navigation("Class");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.AssignmentGroup", b =>
|
||||
{
|
||||
b.HasOne("Entities.Contracts.Assignment", "Assignment")
|
||||
.WithMany("AssignmentGroups")
|
||||
.HasForeignKey("AssignmentId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Entities.Contracts.AssignmentGroup", "ParentAssignmentGroup")
|
||||
.WithMany("ChildAssignmentGroups")
|
||||
.HasForeignKey("ParentGroup")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.Navigation("Assignment");
|
||||
|
||||
b.Navigation("ParentAssignmentGroup");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b =>
|
||||
{
|
||||
b.HasOne("Entities.Contracts.AssignmentGroup", "AssignmentGroup")
|
||||
b.HasOne("Entities.Contracts.AssignmentStruct", "AssignmentGroup")
|
||||
.WithMany("AssignmentQuestions")
|
||||
.HasForeignKey("AssignmentGroupId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
@@ -865,6 +959,22 @@ namespace TechHelper.Server.Migrations
|
||||
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("ParentGroup");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Class", b =>
|
||||
{
|
||||
b.HasOne("Entities.Contracts.User", "HeadTeacher")
|
||||
@@ -914,15 +1024,69 @@ namespace TechHelper.Server.Migrations
|
||||
b.Navigation("Teacher");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.KeyPoint", b =>
|
||||
{
|
||||
b.HasOne("Entities.Contracts.Lesson", "Lesson")
|
||||
.WithMany("KeyPoints")
|
||||
.HasForeignKey("LessonID")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Lesson");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Lesson", b =>
|
||||
{
|
||||
b.HasOne("Entities.Contracts.Textbook", "Textbook")
|
||||
.WithMany("Lessons")
|
||||
.HasForeignKey("TextbookID")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Textbook");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.LessonQuestion", b =>
|
||||
{
|
||||
b.HasOne("Entities.Contracts.Lesson", "Lesson")
|
||||
.WithMany("LessonQuestions")
|
||||
.HasForeignKey("LessonID")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Lesson");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Question", b =>
|
||||
{
|
||||
b.HasOne("Entities.Contracts.User", "Creator")
|
||||
.WithMany("CreatedQuestions")
|
||||
.HasForeignKey("CreatedBy")
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint")
|
||||
.WithMany("Questions")
|
||||
.HasForeignKey("KeyPointId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("Entities.Contracts.Lesson", "Lesson")
|
||||
.WithMany("Questions")
|
||||
.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 =>
|
||||
@@ -935,7 +1099,7 @@ namespace TechHelper.Server.Migrations
|
||||
|
||||
b.HasOne("Entities.Contracts.User", "Grader")
|
||||
.WithMany("GradedSubmissions")
|
||||
.HasForeignKey("GradedBy")
|
||||
.HasForeignKey("GraderId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("Entities.Contracts.User", "Student")
|
||||
@@ -959,7 +1123,7 @@ namespace TechHelper.Server.Migrations
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Entities.Contracts.User", "User")
|
||||
b.HasOne("Entities.Contracts.User", "Student")
|
||||
.WithMany("SubmissionDetails")
|
||||
.HasForeignKey("StudentId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
@@ -973,9 +1137,9 @@ namespace TechHelper.Server.Migrations
|
||||
|
||||
b.Navigation("AssignmentQuestion");
|
||||
|
||||
b.Navigation("Submission");
|
||||
b.Navigation("Student");
|
||||
|
||||
b.Navigation("User");
|
||||
b.Navigation("Submission");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
|
||||
@@ -1035,23 +1199,24 @@ namespace TechHelper.Server.Migrations
|
||||
|
||||
b.Navigation("AssignmentClasses");
|
||||
|
||||
b.Navigation("AssignmentGroups");
|
||||
b.Navigation("ExamStruct")
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Submissions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.AssignmentGroup", b =>
|
||||
{
|
||||
b.Navigation("AssignmentQuestions");
|
||||
|
||||
b.Navigation("ChildAssignmentGroups");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b =>
|
||||
{
|
||||
b.Navigation("SubmissionDetails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.AssignmentStruct", b =>
|
||||
{
|
||||
b.Navigation("AssignmentQuestions");
|
||||
|
||||
b.Navigation("ChildrenGroups");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Class", b =>
|
||||
{
|
||||
b.Navigation("AssignmentClasses");
|
||||
@@ -1061,9 +1226,25 @@ namespace TechHelper.Server.Migrations
|
||||
b.Navigation("ClassTeachers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.KeyPoint", b =>
|
||||
{
|
||||
b.Navigation("Questions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Lesson", b =>
|
||||
{
|
||||
b.Navigation("KeyPoints");
|
||||
|
||||
b.Navigation("LessonQuestions");
|
||||
|
||||
b.Navigation("Questions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Question", b =>
|
||||
{
|
||||
b.Navigation("AssignmentQuestions");
|
||||
|
||||
b.Navigation("ChildrenQuestion");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Submission", b =>
|
||||
@@ -1071,6 +1252,11 @@ namespace TechHelper.Server.Migrations
|
||||
b.Navigation("SubmissionDetails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Textbook", b =>
|
||||
{
|
||||
b.Navigation("Lessons");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.User", b =>
|
||||
{
|
||||
b.Navigation("CreatedAssignments");
|
@@ -77,6 +77,23 @@ namespace TechHelper.Server.Migrations
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "textbook",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
Grade = table.Column<byte>(type: "tinyint unsigned", nullable: false),
|
||||
Title = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
Publisher = table.Column<byte>(type: "tinyint unsigned", nullable: false),
|
||||
SubjectArea = table.Column<byte>(type: "tinyint unsigned", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_textbook", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoleClaims",
|
||||
columns: table => new
|
||||
@@ -207,10 +224,10 @@ namespace TechHelper.Server.Migrations
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
description = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
subject_area = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
subject_area = table.Column<byte>(type: "tinyint unsigned", nullable: false),
|
||||
due_date = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||
total_points = table.Column<float>(type: "float", nullable: true),
|
||||
total_points = table.Column<byte>(type: "tinyint unsigned", nullable: false),
|
||||
score = table.Column<float>(type: "float", nullable: false),
|
||||
created_by = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
created_at = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||
updated_at = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||
@@ -263,36 +280,25 @@ namespace TechHelper.Server.Migrations
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "questions",
|
||||
name: "lesson",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
question_text = table.Column<string>(type: "longtext", maxLength: 65535, nullable: false)
|
||||
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
Title = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
question_type = table.Column<string>(type: "varchar(20)", maxLength: 20, nullable: false)
|
||||
Description = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
correct_answer = table.Column<string>(type: "longtext", maxLength: 65535, nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
difficulty_level = table.Column<string>(type: "varchar(10)", maxLength: 10, nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
subject_area = table.Column<string>(type: "varchar(100)", maxLength: 100, nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
created_by = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
created_at = table.Column<DateTime>(type: "datetime(6)", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
updated_at = table.Column<DateTime>(type: "datetime(6)", rowVersion: true, nullable: false),
|
||||
deleted = table.Column<bool>(type: "tinyint(1)", nullable: false, defaultValue: false),
|
||||
valid_question = table.Column<bool>(type: "tinyint(1)", nullable: false)
|
||||
TextbookID = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_questions", x => x.id);
|
||||
table.PrimaryKey("PK_lesson", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_questions_AspNetUsers_created_by",
|
||||
column: x => x.created_by,
|
||||
principalTable: "AspNetUsers",
|
||||
name: "FK_lesson_textbook_TextbookID",
|
||||
column: x => x.TextbookID,
|
||||
principalTable: "textbook",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
@@ -326,16 +332,16 @@ namespace TechHelper.Server.Migrations
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
assignment = 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),
|
||||
valid_question_group = table.Column<bool>(type: "tinyint(1)", nullable: false)
|
||||
deleted = table.Column<bool>(type: "tinyint(1)", nullable: false, defaultValue: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@@ -350,8 +356,7 @@ namespace TechHelper.Server.Migrations
|
||||
name: "FK_assignment_group_assignments_assignment",
|
||||
column: x => x.assignment,
|
||||
principalTable: "assignments",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
principalColumn: "id");
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
@@ -370,8 +375,7 @@ namespace TechHelper.Server.Migrations
|
||||
graded_by = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
|
||||
graded_at = table.Column<DateTime>(type: "datetime(6)", nullable: true),
|
||||
deleted = table.Column<bool>(type: "tinyint(1)", nullable: false, defaultValue: false),
|
||||
status = table.Column<string>(type: "varchar(15)", maxLength: 15, nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
status = table.Column<int>(type: "int", maxLength: 15, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@@ -457,8 +461,7 @@ namespace TechHelper.Server.Migrations
|
||||
{
|
||||
class_id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
teacher_id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
subject_taught = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
subject_taught = table.Column<byte>(type: "tinyint unsigned", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@@ -478,6 +481,102 @@ namespace TechHelper.Server.Migrations
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "key_point",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
Key = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
LessonID = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_key_point", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_key_point_lesson_LessonID",
|
||||
column: x => x.LessonID,
|
||||
principalTable: "lesson",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "lesson_question",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
Question = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
LessonID = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_lesson_question", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_lesson_question_lesson_LessonID",
|
||||
column: x => x.LessonID,
|
||||
principalTable: "lesson",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "questions",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
question_text = table.Column<string>(type: "longtext", maxLength: 65535, nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
correct_answer = table.Column<string>(type: "longtext", maxLength: 65535, nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
question_type = table.Column<byte>(type: "tinyint unsigned", maxLength: 20, 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),
|
||||
group_state = table.Column<byte>(type: "tinyint unsigned", nullable: false),
|
||||
options = table.Column<string>(type: "longtext", nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
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"),
|
||||
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_at = table.Column<DateTime>(type: "datetime(6)", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
updated_at = table.Column<DateTime>(type: "datetime(6)", rowVersion: true, nullable: false),
|
||||
deleted = table.Column<bool>(type: "tinyint(1)", nullable: false, defaultValue: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_questions", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "FK_questions_AspNetUsers_created_by",
|
||||
column: x => x.created_by,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
table.ForeignKey(
|
||||
name: "FK_questions_key_point_key_point",
|
||||
column: x => x.key_point,
|
||||
principalTable: "key_point",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.SetNull);
|
||||
table.ForeignKey(
|
||||
name: "FK_questions_lesson_lesson",
|
||||
column: x => x.lesson,
|
||||
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");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "assignment_questions",
|
||||
columns: table => new
|
||||
@@ -556,9 +655,9 @@ namespace TechHelper.Server.Migrations
|
||||
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("02a808ba-bd16-4f90-bf2b-0bc42f767e00"), null, "Administrator", "ADMINISTRATOR" },
|
||||
{ new Guid("9e526681-e57e-46b5-a01c-5731b27bfc4a"), null, "Student", "STUDENT" },
|
||||
{ new Guid("dfdfb884-4063-4161-84e0-9c225f4e883c"), null, "Teacher", "TEACHER" }
|
||||
{ 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" }
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
@@ -611,7 +710,8 @@ namespace TechHelper.Server.Migrations
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_assignment_group_assignment",
|
||||
table: "assignment_group",
|
||||
column: "assignment");
|
||||
column: "assignment",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_assignment_group_parent_group",
|
||||
@@ -653,11 +753,47 @@ namespace TechHelper.Server.Migrations
|
||||
table: "classes",
|
||||
column: "head_teacher_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_key_point_LessonID",
|
||||
table: "key_point",
|
||||
column: "LessonID");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_lesson_TextbookID",
|
||||
table: "lesson",
|
||||
column: "TextbookID");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_lesson_question_LessonID",
|
||||
table: "lesson_question",
|
||||
column: "LessonID");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_questions_created_by",
|
||||
table: "questions",
|
||||
column: "created_by");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_questions_key_point",
|
||||
table: "questions",
|
||||
column: "key_point");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_questions_lesson",
|
||||
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",
|
||||
column: "question_text")
|
||||
.Annotation("MySql:IndexPrefixLength", new[] { 20 });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_submission_details_assignment_question_id",
|
||||
table: "submission_details",
|
||||
@@ -719,6 +855,9 @@ namespace TechHelper.Server.Migrations
|
||||
migrationBuilder.DropTable(
|
||||
name: "class_teachers");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "lesson_question");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "submission_details");
|
||||
|
||||
@@ -743,8 +882,17 @@ namespace TechHelper.Server.Migrations
|
||||
migrationBuilder.DropTable(
|
||||
name: "assignments");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "key_point");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUsers");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "lesson");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "textbook");
|
||||
}
|
||||
}
|
||||
}
|
@@ -33,7 +33,7 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("datetime(6)")
|
||||
.HasColumnName("created_at");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
b.Property<Guid>("CreatorId")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("created_by");
|
||||
|
||||
@@ -50,9 +50,12 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("tinyint(1)")
|
||||
.HasColumnName("deleted");
|
||||
|
||||
b.Property<string>("SubjectArea")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext")
|
||||
b.Property<float>("Score")
|
||||
.HasColumnType("float")
|
||||
.HasColumnName("score");
|
||||
|
||||
b.Property<byte>("SubjectArea")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("subject_area");
|
||||
|
||||
b.Property<string>("Title")
|
||||
@@ -61,8 +64,8 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("varchar(255)")
|
||||
.HasColumnName("title");
|
||||
|
||||
b.Property<float?>("TotalPoints")
|
||||
.HasColumnType("float")
|
||||
b.Property<byte>("TotalQuestions")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("total_points");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
@@ -74,7 +77,7 @@ namespace TechHelper.Server.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedBy");
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
@@ -148,60 +151,6 @@ namespace TechHelper.Server.Migrations
|
||||
b.ToTable("assignment_class", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.AssignmentGroup", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<Guid?>("AssignmentId")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("assignment");
|
||||
|
||||
b.Property<string>("Descript")
|
||||
.IsRequired()
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("longtext")
|
||||
.HasColumnName("descript");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("tinyint(1)")
|
||||
.HasDefaultValue(false)
|
||||
.HasColumnName("deleted");
|
||||
|
||||
b.Property<byte>("Number")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("number");
|
||||
|
||||
b.Property<Guid?>("ParentGroup")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("parent_group");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("longtext")
|
||||
.HasColumnName("title");
|
||||
|
||||
b.Property<float?>("TotalPoints")
|
||||
.HasColumnType("float")
|
||||
.HasColumnName("total_points");
|
||||
|
||||
b.Property<bool>("ValidQuestionGroup")
|
||||
.HasColumnType("tinyint(1)")
|
||||
.HasColumnName("valid_question_group");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AssignmentId");
|
||||
|
||||
b.HasIndex("ParentGroup");
|
||||
|
||||
b.ToTable("assignment_group", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@@ -217,6 +166,10 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("datetime(6)")
|
||||
.HasColumnName("created_at");
|
||||
|
||||
b.Property<byte>("Index")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("question_number");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("tinyint(1)")
|
||||
@@ -227,10 +180,6 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("question_id");
|
||||
|
||||
b.Property<byte>("QuestionNumber")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("question_number");
|
||||
|
||||
b.Property<float?>("Score")
|
||||
.HasColumnType("float")
|
||||
.HasColumnName("score");
|
||||
@@ -244,6 +193,61 @@ namespace TechHelper.Server.Migrations
|
||||
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")
|
||||
.HasColumnName("number");
|
||||
|
||||
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")
|
||||
.IsRequired()
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("longtext")
|
||||
.HasColumnName("title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AssignmentId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("ParentGroupId");
|
||||
|
||||
b.ToTable("assignment_group", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Class", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@@ -333,9 +337,8 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("teacher_id");
|
||||
|
||||
b.Property<string>("SubjectTaught")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext")
|
||||
b.Property<byte>("SubjectTaught")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("subject_taught");
|
||||
|
||||
b.HasKey("ClassId", "TeacherId");
|
||||
@@ -345,6 +348,72 @@ namespace TechHelper.Server.Migrations
|
||||
b.ToTable("class_teachers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.KeyPoint", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("varchar(255)");
|
||||
|
||||
b.Property<Guid>("LessonID")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("LessonID");
|
||||
|
||||
b.ToTable("key_point");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Lesson", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<Guid>("TextbookID")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("varchar(255)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TextbookID");
|
||||
|
||||
b.ToTable("lesson");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.LessonQuestion", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<Guid>("LessonID")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<string>("Question")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("LessonID");
|
||||
|
||||
b.ToTable("lesson_question");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Question", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@@ -352,8 +421,7 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<string>("CorrectAnswer")
|
||||
.IsRequired()
|
||||
b.Property<string>("Answer")
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("longtext")
|
||||
.HasColumnName("correct_answer");
|
||||
@@ -365,53 +433,75 @@ namespace TechHelper.Server.Migrations
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<DateTime>("CreatedAt"));
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
b.Property<Guid>("CreatorId")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("created_by");
|
||||
|
||||
b.Property<string>("DifficultyLevel")
|
||||
.IsRequired()
|
||||
b.Property<byte>("DifficultyLevel")
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("varchar(10)")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("difficulty_level");
|
||||
|
||||
b.Property<byte>("GroupState")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("group_state");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("tinyint(1)")
|
||||
.HasDefaultValue(false)
|
||||
.HasColumnName("deleted");
|
||||
|
||||
b.Property<string>("QuestionText")
|
||||
b.Property<Guid?>("KeyPointId")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("key_point");
|
||||
|
||||
b.Property<Guid?>("LessonId")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("lesson");
|
||||
|
||||
b.Property<string>("Options")
|
||||
.HasColumnType("longtext")
|
||||
.HasColumnName("options");
|
||||
|
||||
b.Property<Guid?>("ParentQuestionId")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("parent_question_group_id");
|
||||
|
||||
b.Property<byte>("SubjectArea")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("subject_area");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(65535)
|
||||
.HasColumnType("longtext")
|
||||
.HasColumnName("question_text");
|
||||
|
||||
b.Property<string>("QuestionType")
|
||||
.IsRequired()
|
||||
b.Property<byte>("Type")
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("varchar(20)")
|
||||
.HasColumnType("tinyint unsigned")
|
||||
.HasColumnName("question_type");
|
||||
|
||||
b.Property<string>("SubjectArea")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("varchar(100)")
|
||||
.HasColumnName("subject_area");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.IsConcurrencyToken()
|
||||
.ValueGeneratedOnAddOrUpdate()
|
||||
.HasColumnType("datetime(6)")
|
||||
.HasColumnName("updated_at");
|
||||
|
||||
b.Property<bool>("ValidQuestion")
|
||||
.HasColumnType("tinyint(1)")
|
||||
.HasColumnName("valid_question");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedBy");
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.HasIndex("KeyPointId");
|
||||
|
||||
b.HasIndex("LessonId");
|
||||
|
||||
b.HasIndex("ParentQuestionId");
|
||||
|
||||
b.HasIndex("Title")
|
||||
.HasAnnotation("MySql:IndexPrefixLength", new[] { 20 });
|
||||
|
||||
b.ToTable("questions", (string)null);
|
||||
});
|
||||
@@ -435,7 +525,7 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("datetime(6)")
|
||||
.HasColumnName("graded_at");
|
||||
|
||||
b.Property<Guid?>("GradedBy")
|
||||
b.Property<Guid?>("GraderId")
|
||||
.HasColumnType("char(36)")
|
||||
.HasColumnName("graded_by");
|
||||
|
||||
@@ -455,10 +545,9 @@ namespace TechHelper.Server.Migrations
|
||||
.HasColumnType("float")
|
||||
.HasColumnName("overall_grade");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
b.Property<int>("Status")
|
||||
.HasMaxLength(15)
|
||||
.HasColumnType("varchar(15)")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("status");
|
||||
|
||||
b.Property<Guid>("StudentId")
|
||||
@@ -473,7 +562,7 @@ namespace TechHelper.Server.Migrations
|
||||
|
||||
b.HasIndex("AssignmentId");
|
||||
|
||||
b.HasIndex("GradedBy");
|
||||
b.HasIndex("GraderId");
|
||||
|
||||
b.HasIndex("StudentId");
|
||||
|
||||
@@ -548,6 +637,30 @@ namespace TechHelper.Server.Migrations
|
||||
b.ToTable("submission_details", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Textbook", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<byte>("Grade")
|
||||
.HasColumnType("tinyint unsigned");
|
||||
|
||||
b.Property<byte>("Publisher")
|
||||
.HasColumnType("tinyint unsigned");
|
||||
|
||||
b.Property<byte>("SubjectArea")
|
||||
.HasColumnType("tinyint unsigned");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("textbook");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@@ -658,19 +771,19 @@ namespace TechHelper.Server.Migrations
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = new Guid("d4b41bc3-612e-49dd-aeda-6a98ea0e4e68"),
|
||||
Id = new Guid("895d8f32-714e-4a14-bd97-8fa262b83172"),
|
||||
Name = "Student",
|
||||
NormalizedName = "STUDENT"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("b2e087e6-ea32-46c4-aeb3-09b936cd0cf4"),
|
||||
Id = new Guid("d182c396-c656-42da-965a-d93c17a1f74f"),
|
||||
Name = "Teacher",
|
||||
NormalizedName = "TEACHER"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("ba33e047-8354-4f2c-b8b1-1f46441c28fc"),
|
||||
Id = new Guid("4e65fab9-3315-4474-b92c-bdab5a617e65"),
|
||||
Name = "Administrator",
|
||||
NormalizedName = "ADMINISTRATOR"
|
||||
});
|
||||
@@ -783,7 +896,7 @@ namespace TechHelper.Server.Migrations
|
||||
{
|
||||
b.HasOne("Entities.Contracts.User", "Creator")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedBy")
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
@@ -824,26 +937,9 @@ namespace TechHelper.Server.Migrations
|
||||
b.Navigation("Class");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.AssignmentGroup", b =>
|
||||
{
|
||||
b.HasOne("Entities.Contracts.Assignment", "Assignment")
|
||||
.WithMany("AssignmentGroups")
|
||||
.HasForeignKey("AssignmentId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Entities.Contracts.AssignmentGroup", "ParentAssignmentGroup")
|
||||
.WithMany("ChildAssignmentGroups")
|
||||
.HasForeignKey("ParentGroup")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.Navigation("Assignment");
|
||||
|
||||
b.Navigation("ParentAssignmentGroup");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b =>
|
||||
{
|
||||
b.HasOne("Entities.Contracts.AssignmentGroup", "AssignmentGroup")
|
||||
b.HasOne("Entities.Contracts.AssignmentStruct", "AssignmentGroup")
|
||||
.WithMany("AssignmentQuestions")
|
||||
.HasForeignKey("AssignmentGroupId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
@@ -860,6 +956,22 @@ namespace TechHelper.Server.Migrations
|
||||
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("ParentGroup");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Class", b =>
|
||||
{
|
||||
b.HasOne("Entities.Contracts.User", "HeadTeacher")
|
||||
@@ -909,15 +1021,69 @@ namespace TechHelper.Server.Migrations
|
||||
b.Navigation("Teacher");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.KeyPoint", b =>
|
||||
{
|
||||
b.HasOne("Entities.Contracts.Lesson", "Lesson")
|
||||
.WithMany("KeyPoints")
|
||||
.HasForeignKey("LessonID")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Lesson");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Lesson", b =>
|
||||
{
|
||||
b.HasOne("Entities.Contracts.Textbook", "Textbook")
|
||||
.WithMany("Lessons")
|
||||
.HasForeignKey("TextbookID")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Textbook");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.LessonQuestion", b =>
|
||||
{
|
||||
b.HasOne("Entities.Contracts.Lesson", "Lesson")
|
||||
.WithMany("LessonQuestions")
|
||||
.HasForeignKey("LessonID")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Lesson");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Question", b =>
|
||||
{
|
||||
b.HasOne("Entities.Contracts.User", "Creator")
|
||||
.WithMany("CreatedQuestions")
|
||||
.HasForeignKey("CreatedBy")
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint")
|
||||
.WithMany("Questions")
|
||||
.HasForeignKey("KeyPointId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("Entities.Contracts.Lesson", "Lesson")
|
||||
.WithMany("Questions")
|
||||
.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 =>
|
||||
@@ -930,7 +1096,7 @@ namespace TechHelper.Server.Migrations
|
||||
|
||||
b.HasOne("Entities.Contracts.User", "Grader")
|
||||
.WithMany("GradedSubmissions")
|
||||
.HasForeignKey("GradedBy")
|
||||
.HasForeignKey("GraderId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("Entities.Contracts.User", "Student")
|
||||
@@ -954,7 +1120,7 @@ namespace TechHelper.Server.Migrations
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Entities.Contracts.User", "User")
|
||||
b.HasOne("Entities.Contracts.User", "Student")
|
||||
.WithMany("SubmissionDetails")
|
||||
.HasForeignKey("StudentId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
@@ -968,9 +1134,9 @@ namespace TechHelper.Server.Migrations
|
||||
|
||||
b.Navigation("AssignmentQuestion");
|
||||
|
||||
b.Navigation("Submission");
|
||||
b.Navigation("Student");
|
||||
|
||||
b.Navigation("User");
|
||||
b.Navigation("Submission");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
|
||||
@@ -1030,23 +1196,24 @@ namespace TechHelper.Server.Migrations
|
||||
|
||||
b.Navigation("AssignmentClasses");
|
||||
|
||||
b.Navigation("AssignmentGroups");
|
||||
b.Navigation("ExamStruct")
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Submissions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.AssignmentGroup", b =>
|
||||
{
|
||||
b.Navigation("AssignmentQuestions");
|
||||
|
||||
b.Navigation("ChildAssignmentGroups");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b =>
|
||||
{
|
||||
b.Navigation("SubmissionDetails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.AssignmentStruct", b =>
|
||||
{
|
||||
b.Navigation("AssignmentQuestions");
|
||||
|
||||
b.Navigation("ChildrenGroups");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Class", b =>
|
||||
{
|
||||
b.Navigation("AssignmentClasses");
|
||||
@@ -1056,9 +1223,25 @@ namespace TechHelper.Server.Migrations
|
||||
b.Navigation("ClassTeachers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.KeyPoint", b =>
|
||||
{
|
||||
b.Navigation("Questions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Lesson", b =>
|
||||
{
|
||||
b.Navigation("KeyPoints");
|
||||
|
||||
b.Navigation("LessonQuestions");
|
||||
|
||||
b.Navigation("Questions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Question", b =>
|
||||
{
|
||||
b.Navigation("AssignmentQuestions");
|
||||
|
||||
b.Navigation("ChildrenQuestion");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Submission", b =>
|
||||
@@ -1066,6 +1249,11 @@ namespace TechHelper.Server.Migrations
|
||||
b.Navigation("SubmissionDetails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.Textbook", b =>
|
||||
{
|
||||
b.Navigation("Lessons");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Entities.Contracts.User", b =>
|
||||
{
|
||||
b.Navigation("CreatedAssignments");
|
||||
|
@@ -11,6 +11,7 @@ using System.Text;
|
||||
using TechHelper.Features;
|
||||
using TechHelper.Services;
|
||||
using TechHelper.Server.Services;
|
||||
using TechHelper.Server.Repositories;
|
||||
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
@@ -26,7 +27,7 @@ builder.Services.AddDbContext<ApplicationContext>(options =>
|
||||
).AddUnitOfWork<ApplicationContext>()
|
||||
.AddCustomRepository<Assignment, AssignmentRepository>()
|
||||
.AddCustomRepository<AssignmentAttachment, AssignmentAttachmentRepository>()
|
||||
.AddCustomRepository<AssignmentGroup, AssignmentGroupRepository>()
|
||||
.AddCustomRepository<AssignmentStruct, AssignmentGroupRepository>()
|
||||
.AddCustomRepository<AssignmentQuestion, AssignmentQuestionRepository>()
|
||||
.AddCustomRepository<Class, ClassRepository>()
|
||||
.AddCustomRepository<ClassStudent, ClassStudentRepository>()
|
||||
@@ -85,6 +86,7 @@ builder.Services.AddScoped<IEmailSender, QEmailSender>();
|
||||
builder.Services.AddTransient<IUserRegistrationService, UserRegistrationService>();
|
||||
builder.Services.AddScoped<IClassService, ClassService>();
|
||||
builder.Services.AddScoped<IExamService, ExamService>();
|
||||
builder.Services.AddScoped<IExamRepository, ExamRepository>();
|
||||
|
||||
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
|
92
TechHelper.Server/Repositories/ExamRepository.cs
Normal file
92
TechHelper.Server/Repositories/ExamRepository.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Repository;
|
||||
|
||||
namespace TechHelper.Server.Repositories
|
||||
{
|
||||
public class ExamRepository : IExamRepository
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IRepository<Assignment> _assignmentRepo;
|
||||
private readonly IRepository<AssignmentStruct> _assignmentGroupRepo;
|
||||
private readonly IRepository<Question> _questionRepo;
|
||||
|
||||
public ExamRepository(IUnitOfWork unitOfWork)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_assignmentRepo = _unitOfWork.GetRepository<Assignment>();
|
||||
_assignmentGroupRepo = _unitOfWork.GetRepository<AssignmentStruct>();
|
||||
}
|
||||
|
||||
public async Task<Assignment?> GetFullExamByIdAsync(Guid assignmentId)
|
||||
{
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
return await _assignmentRepo.GetAllAsync(
|
||||
predicate: a => a.CreatorId == userId && !a.IsDeleted);
|
||||
}
|
||||
|
||||
public async Task AddAsync(Assignment assignment)
|
||||
{
|
||||
await _assignmentRepo.InsertAsync(assignment);
|
||||
}
|
||||
|
||||
|
||||
public async Task AddAsync(QuestionGroupDto qg)
|
||||
{
|
||||
if (qg.ValidQuestionGroup)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public async Task AddAsync(AssignmentStruct assignment)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async Task AddAsync(AssignmentQuestion assignment)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task AddAsync(Question assignment)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task AddAsync(AssignmentClass assignment)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
using Entities.Contracts;
|
||||
|
||||
namespace TechHelper.Server.Repository
|
||||
namespace TechHelper.Server.Repositories
|
||||
{
|
||||
public interface IExamRepository
|
||||
{
|
||||
@@ -23,5 +23,16 @@ namespace TechHelper.Server.Repository
|
||||
/// </summary>
|
||||
/// <param name="assignment">要添加的试卷实体。</param>
|
||||
Task AddAsync(Assignment assignment);
|
||||
|
||||
|
||||
|
||||
Task AddAsync(AssignmentStruct assignment);
|
||||
|
||||
Task AddAsync(AssignmentQuestion assignment);
|
||||
|
||||
Task AddAsync(Question assignment);
|
||||
|
||||
Task AddAsync(AssignmentClass assignment);
|
||||
|
||||
}
|
||||
}
|
@@ -5,7 +5,7 @@ using TechHelper.Context;
|
||||
|
||||
namespace TechHelper.Repository
|
||||
{
|
||||
public class AssignmentGroupRepository : Repository<AssignmentGroup>, IRepository<AssignmentGroup>
|
||||
public class AssignmentGroupRepository : Repository<AssignmentStruct>, IRepository<AssignmentStruct>
|
||||
{
|
||||
public AssignmentGroupRepository(ApplicationContext dbContext) : base(dbContext)
|
||||
{
|
||||
|
@@ -10,5 +10,10 @@ namespace TechHelper.Repository
|
||||
public AssignmentRepository(ApplicationContext dbContext) : base(dbContext)
|
||||
{
|
||||
}
|
||||
|
||||
public void THISTEST()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,96 +0,0 @@
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
|
||||
namespace TechHelper.Server.Repository
|
||||
{
|
||||
public class ExamRepository : IExamRepository
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IRepository<Assignment> _assignmentRepo;
|
||||
private readonly IRepository<AssignmentGroup> _assignmentGroupRepo;
|
||||
private readonly IRepository<QuestionGroup> _questionGroupRepo;
|
||||
private readonly IRepository<Question> _questionRepo;
|
||||
|
||||
public ExamRepository(IUnitOfWork unitOfWork)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_assignmentRepo = _unitOfWork.GetRepository<Assignment>();
|
||||
_assignmentGroupRepo = _unitOfWork.GetRepository<AssignmentGroup>();
|
||||
}
|
||||
|
||||
public async Task<Assignment?> GetFullExamByIdAsync(Guid assignmentId)
|
||||
{
|
||||
|
||||
var assignment = await _assignmentRepo.GetFirstOrDefaultAsync(
|
||||
predicate: a => a.Id == assignmentId && !a.IsDeleted,
|
||||
include: source => source
|
||||
.Include
|
||||
(a => a.AssignmentGroups.Where(ag => ag.ParentGroup == null && !ag.IsDeleted)) // 加载根题组
|
||||
.ThenInclude(ag => ag.ChildAssignmentGroups.Where(cag => !cag.IsDeleted)) // 加载子题组
|
||||
.ThenInclude(cag => cag.AssignmentQuestions.Where(aq => !aq.IsDeleted)) // 加载子题组的题目
|
||||
.ThenInclude(aq => aq.Question)
|
||||
.Include(a => a.AssignmentGroups.Where(ag => ag.ParentGroup == null && !ag.IsDeleted)) // 再次从根开始,加载题组下的题目
|
||||
.ThenInclude(ag => ag.AssignmentQuestions.Where(aq => !aq.IsDeleted))
|
||||
.ThenInclude(aq => aq.Question)
|
||||
);
|
||||
|
||||
if (assignment?.AssignmentGroups != null)
|
||||
{
|
||||
foreach (var rootGroup in assignment.AssignmentGroups)
|
||||
{
|
||||
await LoadSubGroupsRecursive(rootGroup);
|
||||
}
|
||||
}
|
||||
|
||||
return assignment;
|
||||
}
|
||||
|
||||
|
||||
private async Task LoadSubGroupsRecursive(AssignmentGroup group)
|
||||
{
|
||||
// EF Core 已经加载了下一层,我们需要确保更深层次的加载
|
||||
var groupWithChildren = await _assignmentGroupRepo.GetFirstOrDefaultAsync(
|
||||
predicate: g => g.Id == group.Id,
|
||||
include: source => source
|
||||
.Include(g => g.ChildAssignmentGroups.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.ChildAssignmentGroups = groupWithChildren.ChildAssignmentGroups;
|
||||
group.AssignmentQuestions = groupWithChildren.AssignmentQuestions;
|
||||
|
||||
if (group.ChildAssignmentGroups != null)
|
||||
{
|
||||
foreach (var child in group.ChildAssignmentGroups)
|
||||
{
|
||||
await LoadSubGroupsRecursive(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Assignment>> GetExamPreviewsByUserAsync(Guid userId)
|
||||
{
|
||||
return await _assignmentRepo.GetAllAsync(
|
||||
predicate: a => a.CreatedBy == userId && !a.IsDeleted);
|
||||
}
|
||||
|
||||
public async Task AddAsync(Assignment assignment)
|
||||
{
|
||||
await _assignmentRepo.InsertAsync(assignment);
|
||||
}
|
||||
|
||||
|
||||
public async Task AddAsync(QuestionGroupDto qg)
|
||||
{
|
||||
if(qg.ValidQuestionGroup)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
TechHelper.Server/Repository/UserRepository.cs
Normal file
17
TechHelper.Server/Repository/UserRepository.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Entities.Contracts;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Context;
|
||||
|
||||
namespace TechHelper.Repository
|
||||
{
|
||||
public class UserRepository : Repository<User>, IRepository<User>
|
||||
{
|
||||
public UserRepository(ApplicationContext dbContext) : base(dbContext)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
namespace TechHelper.Services
|
||||
{
|
||||
public class ApiResponse
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public bool Status { get; set; }
|
||||
public object? Result { get; set; }
|
||||
|
||||
private ApiResponse(bool status, string message, object? result)
|
||||
{
|
||||
Status = status;
|
||||
Message = message;
|
||||
Result = result;
|
||||
}
|
||||
|
||||
public ApiResponse(string message, bool status = false)
|
||||
: this(status, message, null) { }
|
||||
|
||||
|
||||
public ApiResponse(bool status, object result)
|
||||
: this(status, string.Empty, result) { }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个表示成功响应的 ApiResponse 实例。
|
||||
/// </summary>
|
||||
/// <param name="message">成功消息。</param>
|
||||
/// <param name="result">可选的返回数据。</param>
|
||||
/// <returns>ApiResponse 实例。</returns>
|
||||
public static ApiResponse Success(string message = "操作成功。", object? result = null)
|
||||
{
|
||||
return new ApiResponse(true, message, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个表示失败响应的 ApiResponse 实例。
|
||||
/// </summary>
|
||||
/// <param name="message">错误消息。</param>
|
||||
/// <param name="result">可选的错误详情或数据。</param>
|
||||
/// <returns>ApiResponse 实例。</returns>
|
||||
public static ApiResponse Error(string message = "操作失败。", object? result = null)
|
||||
{
|
||||
return new ApiResponse(false, message, result);
|
||||
}
|
||||
}
|
||||
}
|
@@ -197,7 +197,7 @@ namespace TechHelper.Services
|
||||
{
|
||||
ClassId = existingClass.Id,
|
||||
TeacherId = existingClass.Id,
|
||||
SubjectTaught = user.SubjectArea.ToString()
|
||||
SubjectTaught = user.SubjectArea
|
||||
};
|
||||
await _work.GetRepository<ClassTeacher>().InsertAsync(classTeacher);
|
||||
|
||||
|
@@ -1,56 +1,149 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MySqlConnector;
|
||||
using Microsoft.VisualBasic;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Context;
|
||||
using TechHelper.Server.Repositories;
|
||||
using TechHelper.Services;
|
||||
using static TechHelper.Context.AutoMapperProFile;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
|
||||
public class ExamService : IExamService
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IRepository<Assignment> _assignmentRepo;
|
||||
private readonly IRepository<AssignmentGroup> _assignmentGroupRepo;
|
||||
private readonly IRepository<AssignmentQuestion> _assignmentQuestionRepo;
|
||||
private readonly IRepository<Question> _questionRepo;
|
||||
public ExamService(IUnitOfWork unitOfWork, IMapper mapper, UserManager<User> userManager)
|
||||
private readonly IExamRepository _examRepository;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public ExamService(IUnitOfWork unitOfWork, IExamRepository examRepository, IMapper mapper)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_examRepository = examRepository;
|
||||
_mapper = mapper;
|
||||
_userManager = userManager;
|
||||
|
||||
_assignmentRepo = _unitOfWork.GetRepository<Assignment>();
|
||||
_assignmentGroupRepo = _unitOfWork.GetRepository<AssignmentGroup>();
|
||||
_assignmentQuestionRepo = _unitOfWork.GetRepository<AssignmentQuestion>();
|
||||
_questionRepo = _unitOfWork.GetRepository<Question>();
|
||||
}
|
||||
|
||||
private readonly IMapper _mapper;
|
||||
private readonly UserManager<User> _userManager;
|
||||
|
||||
public async Task<ApiResponse> AddAsync(ExamDto model)
|
||||
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())
|
||||
{
|
||||
var result = await SaveParsedExam(model);
|
||||
if (result.Status)
|
||||
if (entry.State == Microsoft.EntityFrameworkCore.EntityState.Added)
|
||||
{
|
||||
return ApiResponse.Success("保存试题成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
return ApiResponse.Error($"保存试题数据失败{result.Message}");
|
||||
if(entry.Entity is Question newQues)
|
||||
{
|
||||
newQues.CreatorId = newAssi.CreatorId;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
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)
|
||||
{
|
||||
return ApiResponse.Error($"保存试题数据失败: {ex.Message}");
|
||||
var newQuestion = _mapper.Map<Question>(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);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var assignment = await _examRepository.GetFullExamByIdAsync(id);
|
||||
if (assignment == null)
|
||||
{
|
||||
|
||||
throw new InvalidOperationException("");
|
||||
}
|
||||
|
||||
return _mapper.Map<AssignmentDto>(assignment);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<AssignmentDto>> GetAllExamPreviewsAsync(Guid userId)
|
||||
{
|
||||
var assignments = await _examRepository.GetExamPreviewsByUserAsync(userId);
|
||||
return _mapper.Map<IEnumerable<AssignmentDto>>(assignments);
|
||||
}
|
||||
|
||||
|
||||
public Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> AddAsync(AssignmentDto model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> UpdateAsync(AssignmentDto model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> DeleteAsync(Guid id)
|
||||
@@ -58,392 +151,10 @@ namespace TechHelper.Server.Services
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
Task<ApiResponse> IExamService.GetAllExamPreviewsAsync(Guid userId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await GetExamByIdAsync(id);
|
||||
return result;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取试题数据失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public Task<ApiResponse> UpdateAsync(ExamDto model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public async Task<IEnumerable<AssignmentGroup>> LoadFullGroupTree(Guid rootGroupId)
|
||||
{
|
||||
var query = @"
|
||||
WITH RECURSIVE GroupTree AS (
|
||||
SELECT
|
||||
ag.*,
|
||||
CAST(ag.`number` AS CHAR(255)) AS path
|
||||
FROM assignment_group ag
|
||||
WHERE ag.id = @rootId
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
c.*,
|
||||
CONCAT(ct.path, '.', c.`number`)
|
||||
FROM assignment_group c
|
||||
INNER JOIN GroupTree ct ON c.parent_group = ct.id
|
||||
)
|
||||
SELECT * FROM GroupTree ORDER BY path;
|
||||
";
|
||||
|
||||
// 执行查询
|
||||
var groups = await _unitOfWork.GetRepository<AssignmentGroup>()
|
||||
.FromSql(query, new MySqlParameter("rootId", rootGroupId))
|
||||
.ToListAsync();
|
||||
|
||||
// 内存中构建树结构
|
||||
var groupDict = groups.ToDictionary(g => g.Id);
|
||||
var root = groupDict[rootGroupId];
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
if (group.ParentGroup != null && groupDict.TryGetValue(group.ParentGroup.Value, out var parent))
|
||||
{
|
||||
parent.ChildAssignmentGroups ??= new List<AssignmentGroup>();
|
||||
parent.ChildAssignmentGroups.Add(group);
|
||||
}
|
||||
}
|
||||
|
||||
return new List<AssignmentGroup> { root };
|
||||
}
|
||||
|
||||
public async Task LoadRecursiveAssignmentGroups(IEnumerable<AssignmentGroup> groups)
|
||||
{
|
||||
foreach (var group in groups.ToList())
|
||||
{
|
||||
|
||||
var loadedGroup = await _unitOfWork.GetRepository<AssignmentGroup>()
|
||||
.GetFirstOrDefaultAsync(
|
||||
predicate: ag => ag.Id == group.Id,
|
||||
include: source => source
|
||||
.Include(ag => ag.AssignmentQuestions.Where(aq => !aq.IsDeleted))
|
||||
.ThenInclude(aq => aq.Question)
|
||||
.Include(ag => ag.ChildAssignmentGroups)
|
||||
);
|
||||
|
||||
if (loadedGroup == null) continue;
|
||||
|
||||
group.ChildAssignmentGroups = loadedGroup.ChildAssignmentGroups;
|
||||
group.AssignmentQuestions = loadedGroup.AssignmentQuestions;
|
||||
|
||||
if (group.ChildAssignmentGroups is { Count: > 0 })
|
||||
{
|
||||
await LoadRecursiveAssignmentGroups(group.ChildAssignmentGroups);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetExamByIdAsync(Guid assignmentId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var assignment = await _unitOfWork.GetRepository<Assignment>().GetFirstOrDefaultAsync(
|
||||
predicate: a => a.Id == assignmentId && !a.IsDeleted);
|
||||
|
||||
if (assignment == null)
|
||||
{
|
||||
return ApiResponse.Error($"找不到 ID 为 {assignmentId} 的试卷。");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 获取所有相关题组和题目,并过滤掉已删除的
|
||||
var allGroups = await _unitOfWork.GetRepository<AssignmentGroup>().GetFirstOrDefaultAsync(
|
||||
predicate: ag => ag.AssignmentId == assignmentId && !ag.IsDeleted,
|
||||
include: source => source
|
||||
.Include(ag => ag.ChildAssignmentGroups)
|
||||
);
|
||||
await LoadRecursiveAssignmentGroups(allGroups.ChildAssignmentGroups);
|
||||
|
||||
if (allGroups == null || !allGroups.ChildAssignmentGroups.Any())
|
||||
{
|
||||
// 试卷存在但没有内容,返回一个空的 ExamDto
|
||||
return ApiResponse.Success("试卷没有内容。", new ExamDto
|
||||
{
|
||||
AssignmentId = assignment.Id,
|
||||
AssignmentTitle = assignment.Title,
|
||||
Description = assignment.Description,
|
||||
SubjectArea = assignment.Submissions.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
var rootGroups = allGroups.ChildAssignmentGroups.ToList();
|
||||
|
||||
var rootqg = new QuestionGroupDto();
|
||||
|
||||
foreach (var ag in rootGroups.OrderBy(g => g.Number))
|
||||
{
|
||||
var agDto = MapAssignmentGroupToDto(ag);
|
||||
rootqg.SubQuestionGroups.Add(agDto);
|
||||
}
|
||||
|
||||
|
||||
// 递归映射到 ExamDto
|
||||
var examDto = new ExamDto
|
||||
{
|
||||
AssignmentId = assignment.Id,
|
||||
AssignmentTitle = assignment.Title,
|
||||
Description = assignment.Description,
|
||||
SubjectArea = assignment.Submissions.ToString(),
|
||||
QuestionGroups = rootqg
|
||||
};
|
||||
|
||||
return ApiResponse.Success("试卷信息已成功获取。", examDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取试卷时发生错误: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public QuestionGroupDto MapAssignmentGroupToDto(AssignmentGroup ag)
|
||||
{
|
||||
// 创建当前节点的DTO
|
||||
var dto = new QuestionGroupDto
|
||||
{
|
||||
Title = ag.Title,
|
||||
Score = (int)(ag.TotalPoints ?? 0),
|
||||
Descript = ag.Descript,
|
||||
SubQuestions = ag.AssignmentQuestions?
|
||||
.OrderBy(aq => aq.QuestionNumber)
|
||||
.Select(aq => new SubQuestionDto
|
||||
{
|
||||
Index = aq.QuestionNumber,
|
||||
Stem = aq.Question?.QuestionText,
|
||||
Score = aq.Score ?? 0,
|
||||
SampleAnswer = aq.Question?.CorrectAnswer,
|
||||
QuestionType = aq.Question?.QuestionType.ToString(),
|
||||
DifficultyLevel = aq.Question?.DifficultyLevel.ToString(),
|
||||
Options = new List<OptionDto>() // 根据需要初始化
|
||||
}).ToList() ?? new List<SubQuestionDto>(),
|
||||
SubQuestionGroups = new List<QuestionGroupDto>() // 初始化子集合
|
||||
};
|
||||
|
||||
// 递归处理子组
|
||||
if (ag.ChildAssignmentGroups != null && ag.ChildAssignmentGroups.Count > 0)
|
||||
{
|
||||
foreach (var child in ag.ChildAssignmentGroups.OrderBy(c => c.Number))
|
||||
{
|
||||
var childDto = MapAssignmentGroupToDto(child); // 递归获取子DTO
|
||||
dto.SubQuestionGroups.Add(childDto); // 添加到当前节点的子集合
|
||||
}
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
private List<QuestionGroupDto> MapAssignmentGroupsToDto2(
|
||||
List<AssignmentGroup> currentLevelGroups,
|
||||
IEnumerable<AssignmentGroup> allFetchedGroups)
|
||||
{
|
||||
var dtos = new List<QuestionGroupDto>();
|
||||
|
||||
foreach (var group in currentLevelGroups.OrderBy(g => g.Number))
|
||||
{
|
||||
var groupDto = new QuestionGroupDto
|
||||
{
|
||||
|
||||
Title = group.Title,
|
||||
Score = (int)(group.TotalPoints ?? 0),
|
||||
Descript = group.Descript,
|
||||
SubQuestions = group.AssignmentQuestions
|
||||
.OrderBy(aq => aq.QuestionNumber)
|
||||
.Select(aq => new SubQuestionDto
|
||||
{
|
||||
Index = aq.QuestionNumber,
|
||||
Stem = aq.Question.QuestionText,
|
||||
Score = aq.Score ?? 0,
|
||||
SampleAnswer = aq.Question.CorrectAnswer,
|
||||
QuestionType = aq.Question.QuestionType.ToString(),
|
||||
DifficultyLevel = aq.Question.DifficultyLevel.ToString(),
|
||||
Options = new List<OptionDto>()
|
||||
}).ToList(),
|
||||
// 递归映射子题组
|
||||
SubQuestionGroups = MapAssignmentGroupsToDto2(
|
||||
allFetchedGroups.Where(ag => ag.ParentGroup == group.Id && !ag.IsDeleted).ToList(),
|
||||
allFetchedGroups)
|
||||
};
|
||||
dtos.Add(groupDto);
|
||||
}
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public async Task<TechHelper.Services.ApiResponse> SaveParsedExam(ExamDto examData)
|
||||
{
|
||||
// 获取当前登录用户
|
||||
var currentUser = await _userManager.FindByEmailAsync(examData.CreaterEmail);
|
||||
if (currentUser == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到当前登录用户,无法保存试题。");
|
||||
}
|
||||
var currentUserId = currentUser.Id;
|
||||
|
||||
try
|
||||
{
|
||||
Guid assignmentId;
|
||||
|
||||
// 创建新的 Assignment 实体
|
||||
var newAssignment = new Assignment
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Title = examData.AssignmentTitle,
|
||||
Description = examData.Description,
|
||||
SubjectArea = examData.SubjectArea,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
CreatedBy = currentUserId,
|
||||
IsDeleted = false
|
||||
};
|
||||
await _assignmentRepo.InsertAsync(newAssignment);
|
||||
assignmentId = newAssignment.Id;
|
||||
|
||||
|
||||
// 从 ExamDto.QuestionGroups 获取根题组。
|
||||
// 确保只有一个根题组,因为您的模型是“试卷只有一个根节点”。
|
||||
if (examData.QuestionGroups == null)
|
||||
{
|
||||
throw new ArgumentException("试卷必须包含且只能包含一个根题组。");
|
||||
}
|
||||
|
||||
await ProcessAndSaveAssignmentGroupsRecursive(
|
||||
examData.QuestionGroups,
|
||||
examData.SubjectArea.ToString(),
|
||||
assignmentId,
|
||||
null, // 根题组没有父级
|
||||
currentUserId);
|
||||
|
||||
if (await _unitOfWork.SaveChangesAsync() > 0)
|
||||
{
|
||||
return ApiResponse.Success("试卷数据已成功保存。", new ExamDto { AssignmentId = assignmentId, AssignmentTitle = examData.AssignmentTitle });
|
||||
}
|
||||
else
|
||||
{
|
||||
return ApiResponse.Success("没有新的试卷数据需要保存。");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"保存试卷数据失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ProcessAndSaveAssignmentGroupsRecursive(
|
||||
QuestionGroupDto qgDto,
|
||||
string subjectarea,
|
||||
Guid assignmentId,
|
||||
Guid? parentAssignmentGroupId,
|
||||
Guid createdById)
|
||||
{
|
||||
if (qgDto.ValidQuestionGroup)
|
||||
{
|
||||
await SaveQuestionGroup(qgDto);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte groupNumber = 1;
|
||||
|
||||
|
||||
var newAssignmentGroup = new AssignmentGroup
|
||||
{
|
||||
Id = Guid.NewGuid(), // 后端生成 GUID
|
||||
Title = qgDto.Title,
|
||||
Descript = qgDto.Descript,
|
||||
TotalPoints = qgDto.Score,
|
||||
Number = (byte)qgDto.Index,
|
||||
ValidQuestionGroup = qgDto.ValidQuestionGroup,
|
||||
ParentGroup = parentAssignmentGroupId,
|
||||
AssignmentId = parentAssignmentGroupId == null ? assignmentId : (Guid?)null,
|
||||
IsDeleted = false
|
||||
};
|
||||
await _unitOfWork.GetRepository<AssignmentGroup>().InsertAsync(newAssignmentGroup);
|
||||
|
||||
// 处理子题目
|
||||
uint questionNumber = 1;
|
||||
foreach (var sqDto in qgDto.SubQuestions.OrderBy(s => s.Index))
|
||||
{
|
||||
var newQuestion = _mapper.Map<Question>(sqDto);
|
||||
newQuestion.Id = Guid.NewGuid();
|
||||
newQuestion.CreatedBy = createdById;
|
||||
newQuestion.CreatedAt = DateTime.UtcNow;
|
||||
newQuestion.UpdatedAt = DateTime.UtcNow;
|
||||
newQuestion.IsDeleted = false;
|
||||
newQuestion.SubjectArea = EnumMappingHelpers.ParseEnumSafe(subjectarea, SubjectAreaEnum.Unknown);
|
||||
|
||||
await _unitOfWork.GetRepository<Question>().InsertAsync(newQuestion);
|
||||
|
||||
var newAssignmentQuestion = new AssignmentQuestion
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
QuestionId = newQuestion.Id,
|
||||
QuestionNumber = (byte)questionNumber,
|
||||
AssignmentGroupId = newAssignmentGroup.Id,
|
||||
Score = sqDto.Score,
|
||||
IsDeleted = false,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
await _unitOfWork.GetRepository<AssignmentQuestion>().InsertAsync(newAssignmentQuestion);
|
||||
|
||||
questionNumber++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 递归处理子题组
|
||||
// 这里需要遍历 SubQuestionGroups,并对每个子组进行递归调用
|
||||
foreach (var subQgDto in qgDto.SubQuestionGroups.OrderBy(s => s.Index))
|
||||
{
|
||||
await ProcessAndSaveAssignmentGroupsRecursive(
|
||||
subQgDto, // 传入当前的子题组 DTO
|
||||
subjectarea,
|
||||
assignmentId, // 顶层 AssignmentId 依然传递下去,但子组不会直接使用它
|
||||
newAssignmentGroup.Id, // 将当前题组的 ID 作为下一层递归的 parentAssignmentGroupId
|
||||
createdById);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveQuestionGroup(QuestionGroupDto qgDto)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAllExamPreview(Guid user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var assignments = await _unitOfWork.GetRepository<Assignment>().GetAllAsync(
|
||||
predicate: a => a.CreatedBy == user && !a.IsDeleted);
|
||||
|
||||
if (assignments.Any())
|
||||
{
|
||||
var exam = _mapper.Map<IEnumerable<ExamDto>>(assignments);
|
||||
return ApiResponse.Success(result: exam);
|
||||
}
|
||||
|
||||
return ApiResponse.Error("你还没有创建任何试卷");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"查询出了一点问题 , 详细信息为: {ex.Message}, 请稍后再试");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,123 +0,0 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Server.Repository;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
|
||||
public class ExamService2 : IExamService2
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IExamRepository _examRepository;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public ExamService2(IUnitOfWork unitOfWork, IExamRepository examRepository, IMapper mapper)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_examRepository = examRepository;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<Guid> CreateExamAsync(ExamDto examDto, Guid creatorId)
|
||||
{
|
||||
if (examDto.QuestionGroups == null)
|
||||
{
|
||||
throw new ArgumentException("试卷必须包含一个根题组。");
|
||||
}
|
||||
|
||||
// 使用 AutoMapper 将 DTO 映射到实体
|
||||
var assignment = _mapper.Map<Assignment>(examDto);
|
||||
|
||||
// 设置后端生成的属性
|
||||
assignment.Id = Guid.NewGuid();
|
||||
assignment.CreatedBy = creatorId;
|
||||
assignment.CreatedAt = DateTime.UtcNow;
|
||||
|
||||
// 递归设置所有子实体的ID和关联关系
|
||||
SetEntityIdsAndRelations(assignment.AssignmentGroups.First(), assignment.Id, creatorId);
|
||||
|
||||
await _examRepository.AddAsync(assignment);
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
|
||||
return assignment.Id;
|
||||
}
|
||||
|
||||
private void SetEntityIdsAndRelations(AssignmentGroup group, Guid? assignmentId, Guid creatorId)
|
||||
{
|
||||
group.Id = Guid.NewGuid();
|
||||
group.AssignmentId = assignmentId;
|
||||
|
||||
foreach (var aq in group.AssignmentQuestions)
|
||||
{
|
||||
aq.Id = Guid.NewGuid();
|
||||
aq.AssignmentGroupId = group.Id;
|
||||
aq.Question.Id = Guid.NewGuid();
|
||||
aq.Question.CreatedBy = creatorId;
|
||||
aq.CreatedAt = DateTime.UtcNow;
|
||||
// ... 其他默认值
|
||||
}
|
||||
|
||||
foreach (var childGroup in group.ChildAssignmentGroups)
|
||||
{
|
||||
// 子题组的 AssignmentId 为 null,通过 ParentGroup 关联
|
||||
SetEntityIdsAndRelations(childGroup, null, creatorId);
|
||||
childGroup.ParentGroup = group.Id;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ExamDto> GetExamByIdAsync(Guid id)
|
||||
{
|
||||
var assignment = await _examRepository.GetFullExamByIdAsync(id);
|
||||
if (assignment == null)
|
||||
{
|
||||
|
||||
throw new InvalidOperationException("");
|
||||
}
|
||||
|
||||
return _mapper.Map<ExamDto>(assignment);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ExamDto>> GetAllExamPreviewsAsync(Guid userId)
|
||||
{
|
||||
var assignments = await _examRepository.GetExamPreviewsByUserAsync(userId);
|
||||
return _mapper.Map<IEnumerable<ExamDto>>(assignments);
|
||||
}
|
||||
|
||||
public async Task AddAsync(QuestionGroupDto qg)
|
||||
{
|
||||
if (qg.ValidQuestionGroup)
|
||||
{
|
||||
var mapQG = _mapper.Map<QuestionGroup>(qg);
|
||||
}
|
||||
}
|
||||
|
||||
public Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> AddAsync(ExamDto model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> UpdateAsync(ExamDto model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -3,7 +3,7 @@ using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public interface IAssignmentGroupService : IBaseService<AssignmentGroup, Guid>
|
||||
public interface IAssignmentGroupService : IBaseService<AssignmentStruct, Guid>
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@@ -4,9 +4,23 @@ using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public interface IExamService : IBaseService<ExamDto, Guid>
|
||||
public interface IExamService : IBaseService<AssignmentDto, Guid>
|
||||
{
|
||||
Task<ApiResponse> GetAllExamPreview(Guid user);
|
||||
QuestionGroupDto MapAssignmentGroupToDto(AssignmentGroup ag);
|
||||
/// <summary>
|
||||
/// 根据 ID 获取试卷 DTO。
|
||||
/// </summary>
|
||||
Task<AssignmentDto> GetExamByIdAsync(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定用户的所有试卷预览。
|
||||
/// </summary>
|
||||
Task<ApiResponse> GetAllExamPreviewsAsync(Guid userId);
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的试卷。
|
||||
/// </summary>
|
||||
/// <returns>创建成功的试卷ID</returns>
|
||||
Task<ApiResponse> CreateExamAsync(AssignmentDto examDto);
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -1,26 +0,0 @@
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public interface IExamService2 : IBaseService<ExamDto, Guid>
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据 ID 获取试卷 DTO。
|
||||
/// </summary>
|
||||
Task<ExamDto> GetExamByIdAsync(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定用户的所有试卷预览。
|
||||
/// </summary>
|
||||
Task<IEnumerable<ExamDto>> GetAllExamPreviewsAsync(Guid userId);
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的试卷。
|
||||
/// </summary>
|
||||
/// <returns>创建成功的试卷ID</returns>
|
||||
Task<Guid> CreateExamAsync(ExamDto examDto, Guid creatorId);
|
||||
|
||||
}
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
using Entities.Contracts;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public interface IQuestionGroupService : IBaseService<QuestionGroup, Guid>
|
||||
{
|
||||
}
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public class QuestionGroupService : IAssignmentGroupService
|
||||
{
|
||||
|
||||
private readonly IUnitOfWork _work;
|
||||
// 如果不再需要 AutoMapper 进行实体到 DTO 的映射,可以移除 _mapper 字段
|
||||
// 但如果 AutoMapper 在其他服务中用于其他映射,或者将来可能需要,可以保留
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IExamService _examService;
|
||||
|
||||
public QuestionGroupService(IUnitOfWork work, IMapper mapper, IExamService examService)
|
||||
{
|
||||
_work = work;
|
||||
_mapper = mapper;
|
||||
_examService = examService;
|
||||
}
|
||||
|
||||
|
||||
public Task<ApiResponse> AddAsync(AssignmentGroup model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var result = await _work.GetRepository<AssignmentGroup>().GetFirstOrDefaultAsync(predicate: ag => ag.Id == id);
|
||||
QuestionGroupDto qgd = new QuestionGroupDto();
|
||||
if (result != null)
|
||||
{
|
||||
qgd = _examService.MapAssignmentGroupToDto(result);
|
||||
return ApiResponse.Success(result: qgd);
|
||||
}
|
||||
return ApiResponse.Error("没找到问题组");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"出现了一点问题: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public Task<ApiResponse> UpdateAsync(AssignmentGroup model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@@ -31,12 +31,12 @@ namespace TechHelper.Server.Services
|
||||
{
|
||||
// 可以在此处进行业务逻辑校验,例如检查题目是否已存在
|
||||
var existingQuestion = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
|
||||
predicate: q => q.QuestionText == model.QuestionText && !q.IsDeleted
|
||||
predicate: q => q.Title == model.Title && !q.IsDeleted
|
||||
);
|
||||
|
||||
if (existingQuestion != null)
|
||||
{
|
||||
return ApiResponse.Error($"题目 '{model.QuestionText}' 已存在,请勿重复添加。");
|
||||
return ApiResponse.Error($"题目 '{model.Title}' 已存在,请勿重复添加。");
|
||||
}
|
||||
|
||||
// 设置创建时间、创建者等通用属性
|
||||
@@ -44,8 +44,7 @@ namespace TechHelper.Server.Services
|
||||
model.CreatedAt = DateTime.UtcNow;
|
||||
model.UpdatedAt = DateTime.UtcNow;
|
||||
model.IsDeleted = false;
|
||||
model.ValidQuestion = true; // 假设新添加的题目默认为有效
|
||||
// model.CreatedBy = ... // 实际应用中,这里应该从当前用户上下文获取
|
||||
|
||||
|
||||
await _work.GetRepository<Question>().InsertAsync(model);
|
||||
await _work.SaveChangesAsync();
|
||||
@@ -90,7 +89,7 @@ namespace TechHelper.Server.Services
|
||||
try
|
||||
{
|
||||
var question = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
|
||||
predicate: q => q.QuestionText == title && !q.IsDeleted
|
||||
predicate: q => q.Title == title && !q.IsDeleted
|
||||
);
|
||||
|
||||
if (question == null)
|
||||
@@ -119,10 +118,10 @@ namespace TechHelper.Server.Services
|
||||
var distinctTitles = titles.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
|
||||
|
||||
var existingQuestions = await _work.GetRepository<Question>().GetAllAsync(
|
||||
predicate: q => distinctTitles.Contains(q.QuestionText) && !q.IsDeleted
|
||||
predicate: q => distinctTitles.Contains(q.Title) && !q.IsDeleted
|
||||
);
|
||||
|
||||
var existingQuestionTexts = new HashSet<string>(existingQuestions.Select(q => q.QuestionText), StringComparer.OrdinalIgnoreCase);
|
||||
var existingQuestionTexts = new HashSet<string>(existingQuestions.Select(q => q.Title), StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var resultDictionary = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var title in titles)
|
||||
@@ -146,7 +145,7 @@ namespace TechHelper.Server.Services
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
predicate = predicate.And(q => q.QuestionText.Contains(query.Search));
|
||||
predicate = predicate.And(q => q.Title.Contains(query.Search));
|
||||
}
|
||||
|
||||
Func<IQueryable<Question>, IOrderedQueryable<Question>> orderBy = null;
|
||||
@@ -214,12 +213,12 @@ namespace TechHelper.Server.Services
|
||||
|
||||
// 检查更新后的题目文本是否与现有其他题目重复
|
||||
var duplicateCheck = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
|
||||
predicate: q => q.Id != model.Id && q.QuestionText == model.QuestionText && !q.IsDeleted
|
||||
predicate: q => q.Id != model.Id && q.Title == model.Title && !q.IsDeleted
|
||||
);
|
||||
|
||||
if (duplicateCheck != null)
|
||||
{
|
||||
return ApiResponse.Error($"题目文本 '{model.QuestionText}' 已被其他题目占用,请修改。");
|
||||
return ApiResponse.Error($"题目文本 '{model.Title}' 已被其他题目占用,请修改。");
|
||||
}
|
||||
|
||||
// 手动复制属性或使用 AutoMapper (如果保留了 _mapper 字段)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
|
@@ -6,7 +6,7 @@
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"XSDB": "Server=mysql.eazygame.cn;Port=13002;Database=test;User=root;Password=wx1998WX"
|
||||
"XSDB": "Server=mysql.eazygame.cn;Port=13002;Database=test1;User=root;Password=wx1998WX"
|
||||
},
|
||||
"JWTSettings": {
|
||||
"securityKey": "MxcxQHVYVDQ0U3lqWkIwdjZlSGx4eFp6YnFpUGxodmc5Y3hPZk5vWm9MZEg2Y0I=",
|
||||
|
Reference in New Issue
Block a user