NHibernate中有不同类型答案的问题
我正试图找到问卷调查问题的整洁解决方案。 让我们说我有一个Questionnaire
,其中包含一些Answer
,例如
public class Questionnaire { public virtual ISet Answers {get;set;} }
答案需要根据问题的不同类型,例如出生日期,十分之一,你为什么这么认为等等。
我的第一个想法是这样的:
public class Question { public virtual QuestionType TypeOfQuestion {get;set;} public virtual string PromptText {get;set;} } public class Answer { public virtual Question Question {get;set;} } public class DateTimeAnswer : Answer { public virtual DateTime Response {get;set;} } public class IntegerAnswer : Answer { public virtual int Response {get;set;} } // etc.
显而易见的问题是,从调查问卷中,无法访问Response
属性:
questionnaire.Answers[0].Response; // compile error
这同样适用于接口。 使用通用接口会更好,例如:
public interface IAnswer { public virtual Question Question {get;set;} public virtual T Response {get;set;} } public class DateTimeAnswer : IAnswer {}
然后问题出现在Questionnaire
类中,因为必须提供IAnswer的类型:
public class Questionnaire { public virtual ISet<IAnswer> Answers {get;set;} }
显然,我不希望有许多IAnswer的集合,每个集合都有不同的类型。 我可以用
ISet<IAnswer>
但是NHibernate不喜欢它。
我意识到某处需要妥协,但我不确定哪个是最漂亮的。 你会怎么做?
我认为子类化问题和答案是一个很好的计划 – 摆脱QuestionType枚举。
然后,您可以在Question上使用MakeAnswer(字符串)抽象方法,它为您封装了许多逻辑,并且可以在必要时进行类型转换等。
我对Rob的答案的一般问题的解决方案是这样的:
public interface IAnswer { Question Question { get; } void Respond(IAnswerFormatter formatter); }
IAnswerFormatter
看起来像这样:
public interface IAnswerFormatter { void Format(string value); void Format(DateTime value); ... }
而DateTimeAnswer看起来像这样:
public class DateTimeAnswer : IAnswer { public DateTimeAnswer(Question question, DateTime value) { Question = question; } public Question Question { get; protected set; } protected DateTime Response {get; set;} public virtual void Respond(IAnswerFormatter formatter) { formatter.Write(Response); } }
而DateTimeQuestion可能如下所示:
public class DateTimeQuestion : Question { public IAnswer MakeAnswer(string value) { // Ignoring error handling here return new DateTimeAnswer(this, DateTime.Parse(value)); } }
这样你的答案可以用自己的方式保存值,你的NH映射可以指定它在数据库中的外观(我建议使用鉴别器进行映射)你的问题可以负责从一般响应中创建答案。
有趣的问题..
我的意见/想法:
- 正如史蒂夫所说 – 摆脱那个令人讨厌的
QuestionType
枚举! - 删除
ISet
– 我认为它不会增加任何值..
我会按照以下方式思考:
public class Questionnaire { public AnswerCollection Answers { get; set; } } public class AnswerCollection : Collection { // Subclassed Collection for Add/Remove Semantics etc. } public abstract class Answer : IAnswer
这个想法在这里,我们需要了解你正在对所有对象做的事情的本质,这可能只是显示答案..我们通过generics添加类型安全,所以我们可以肯定我们不能创建没有类型参数的新响应..
然后,我们可以非常确定进出的内容仅限于我们实施的答案类型。 NHIB应该没有真正解决这个问题,因为它知道它需要什么。
虽然它很糟糕,我们有从该集合回来的Answer
的“ object
”版本,这就是该集合的内容, Answers 。
这有帮助吗? 🙂
将答案存储在完整的数据模型中是否真的有意义? 你打算和他们一起做什么?
最可能的候选人似乎是报告,在这种情况下,您可能希望查看CQRS(命令查询责任分离)样式。 相反,你会有一个QuestionnaireCompletedCommand,其中包含一个答案列表,然后你会以某种方式持续存在可以针对它们运行报告的答案。
当您拥有业务逻辑(您可能)时,数据模型很棒,但如果您没有任何业务逻辑,则可能只会使解决方案不必要地复杂化。 说到看看CQRS时的复杂性,我不一定是指事件采购部分。 这是一个很少人需要的巨大复杂因素。