我正在玩RavenDb并正在构建某种测验。有不同类型的问题: - 多项选择(A,B,C或D?) - 日期(在什么日期......?) - 数量(多少......?)
我所做的是创建一个带有属性Question
的基类问题,其中包含用户提供的字符串和答案列表的问题。
public class Question
{
public string Question { get; set; }
public List<Answer> Answers { get; set; }
}
然后我创建了多个继承自Question
的子类。
例如,NumberQuestion
包含属性MinimumValue
和MaximumValue
,因为每个问题存在差异。
我希望用户给出答案,并将该答案保存到数据库中。问题是,答案可以是不同的类型,如DateTime,float或integer(多选)。 我的问题是,在RavenDb中保存答案的最佳方法是什么?
这就是我目前正在做的事情:
public class Answer
{
public User User { get; set; }
public string AnswerString { get; set; }
public string AnswerType { get; set; }
}
我在这里做的是将答案保存为字符串并保存类型(DateTime,float等),以便稍后解析。
它有效,但我不太喜欢它。必须有另一种更好的方式。
答案 0 :(得分:4)
如果要在同一属性中存储多个类型,则只需将该属性声明为公共基类型。在你的情况下,object
会做得很好。序列化后,您将在json中获得额外的$type
个字段,这样就可以将它们反序列化为适当的形式。
让我们看看我是否可以就您的特定域模型提供一些建议。
不要将可能的答案与实际答案混淆。给出这些不同的名称以保持它们的直线。我将使用Choice
来表示问题的可能答案,并使用Answer
来表示用户给出的实际答案。
注意聚合实体的位置。这些最终在RavenDB中作为实际文档并获得Id。在您的情况下,我只看到两个 - Question
和Exam
。
尝试使用此尺寸:
public abstract class Question
{
public string Id { get; set; }
public string QuestionText { get; set; }
}
public class ValueQuestion : Question
{
public object CorrectValue { get; set; }
}
public class RangeQuestion : Question
{
public object MinCorrectValue { get; set; }
public object MaxCorrectValue { get; set; }
}
public class MultipleChoiceQuestion : Question
{
public int NumberOfChoicesAllowed { get; set; }
public List<MultipleChoiceOption> Choices { get; set; }
}
public class MultipleChoiceOption
{
public char Letter { get; set; }
public bool Correct { get; set; }
public object Value { get; set; }
}
public class EssayQuestion : Question
{
public int MinAnswerLength { get; set; }
public int MaxAnswerLength { get; set; }
}
public class Exam
{
public string Id { get; set; }
public string UserId { get; set; }
public DateTime Taken { get; set; }
public decimal Score { get; set; }
public List<Answer> Answers { get; set; }
}
public class Answer
{
public string QuestionId { get; set; }
public bool Correct { get; set; }
public object Value { get; set; }
}
泛型可能很诱人,但我认为你会发现它们并没有给你带来太大的收益。最后,您将在文档中使用相同的结构,并在数据库中使用相同的布局。可能唯一的区别是$type
字段用于不同的地方。
如果您想尝试基于泛型的解决方案,请尝试以下方法:
public abstract class Question
{
public string Id { get; set; }
public string QuestionText { get; set; }
}
public class ValueQuestion<T> : Question
{
public T CorrectValue { get; set; }
}
public class RangeQuestion<T> : Question
{
public T MinCorrectValue { get; set; }
public T MaxCorrectValue { get; set; }
}
public class MultipleChoiceQuestion<T> : Question
{
public int NumberOfChoicesAllowed { get; set; }
public List<MultipleChoiceOption<T>> Choices { get; set; }
}
public class MultipleChoiceOption<T>
{
public char Letter { get; set; }
public bool Correct { get; set; }
public T Value { get; set; }
}
public class EssayQuestion : Question
{
public int MinAnswerLength { get; set; }
public int MaxAnswerLength { get; set; }
}
public class Exam
{
public string Id { get; set; }
public string UserId { get; set; }
public DateTime Taken { get; set; }
public decimal Score { get; set; }
public List<IAnswer> Answers { get; set; }
}
public interface IAnswer
{
string QuestionId { get; set; }
bool Correct { get; set; }
}
public class Answer<T> : IAnswer
{
public string QuestionId { get; set; }
public bool Correct { get; set; }
public T Value { get; set; }
}
答案 1 :(得分:0)
你可以使用泛型。创建Question
的通用类TAnswer
,其中TAnswer
必须从抽象类Answer
继承。特定问题类将从该类继承:
public abstract class Question<TAnswer> where TAnswer : Answer
{
public Guid Id { get; set; }
public string Question { get; set; }
public List<TAnswer> Answers { get; set; }
}
public class DateQuestion : Question<DateAnswer>
{
//...
}
您用于答案的类都继承自基类Answer
,它引用了它所属的问题以及已经回答它的用户。然后,您可以为每种答案类型设置一个单独的表,从而防止解析类型,同时保持问题,答案和回答它们的用户之间的联系
public abstract class Answer {
public Guid QuestionId { get; set; }
public Guid UserId { get; set; }
}
public class MultipleChoiceAnswer :Answer {
//...
}
public class DateAnswer : Answer {
//...
}