web-dev-qa-db-ja.com

派生クラスを選択し、エンティティフレームワークにプロパティを追加する

次のStudentGroupクラスがあります。

public class StudentGroup
{
    [Key]
    public int Id { get; set; }

    //the set of peers who will review the work of the StudentGroup
    [ForeignKey("PeerReviewGroupId")]
    public PeerReviewGroup PeerReviewGroup { get; set; }
    public int? PeerReviewGroupId { get; set; }

    public IEnumerable<GroupMembership> GroupMemberships { get; set; }
}

このクラスから派生したPeerReviewGroupには、2つの新しいプロパティがあります。

public class PeerReviewGroup: StudentGroup
{
    [ForeignKey("StudentToReview")]
    public ApplicationUser StudentToReview { get; set; }
    public string StudentToReviewId { get; set; }

    [ForeignKey("StudentGroupToReview")]
    public StudentGroup StudentGroupToReview { get; set; }
    public string StudentGroupToReviewId { get; set; }

}

PeerReviewGroupは、個人(つまりStudentToReview)または別のグループ(つまりStudentrGoup)に割り当てることができます。したがって、これらの値のいずれかはnullである必要があります。

代わりに、2つのクラスを駆動できます。

public class PeerReviewGroupForIndividuals: StudentGroup
{
    [ForeignKey("StudentToReview")]
    public ApplicationUser StudentToReview { get; set; }
    public string StudentToReviewId { get; set; }
}

public class PeerReviewGroupForGroups: StudentGroup
{
    [ForeignKey("StudentGroupToReview")]
    public StudentGroup StudentGroupToReview { get; set; }
    public string StudentGroupToReviewId { get; set; }

}

これが望ましいのか、そうでないのか、どちらのアプローチがベストプラクティスなのでしょうか。 2つのクラスを派生させると状況が複雑になると思います。助言がありますか?

2
renakre

私はあなたがmay問題を過度に複雑にしていると感じています。

次のアプローチが機能しないのはなぜですか?

public class StudentGroup
{
    [Key]
    public int Id {get; set;}

    //the students who comprise the group
    //the list can contain 1 to n users
    public List<ApplicationUser> Members
}

public class PeerReviewSession
{
    //this is the group of students who are performing the review
    [ForeignKey("GroupReviewing")]
    public StudentGroup GroupReviewing {get; set;}

    //this is the group of students who are being reviewed
    [ForeignKey("GroupReviewed")]
    public StudentGroup GroupReviewed {get; set;}

}

シナリオ全体がわからないため、ここにいくつかの要素が欠けている可能性があります。ただし、基本的な前提がコメントで提案したとおりである場合:

「2つのグループの学生がいて、1つのグループが他のグループをレビューできる」

次に、これが本当に必要なすべてです。

2
Shai Cohen

PeerReviewGroupは、個人(つまりStudentToReview)または別のグループ(つまりStudentGroup)に割り当てることができます。したがって、これらの値のいずれかはnullである必要があります。

代わりに、2つのクラスを運転できます

額面では、あなたの解釈は正しいです。同時に両方のプロパティが必要になることはないため、同じエンティティ/テーブルにそれらを配置する目的はありません。

ただし、特定の(既存の)ピアレビューグループを今日の学生と明日の学生グループに割り当てることができる可能性は十分にあるようです。エンティティを分割した場合は、生徒またはグループに割り当てられるように切り替わるたびに、ピアレビューグループを再作成する必要があります。

あなたのアプリケーションについて、その呼び出しを行うのに十分な知識がありません。

  • 査読グループが複数の割り当てを長期間にわたって存続させる永続的なエンティティである場合は、プロパティをまとめて維持するか、より抽象化された構造を探します(以下の提案を参照)。
  • ピアレビューグループが、新しい割り当てが行われるたびに再作成される破棄可能なエンティティである場合、継承を使用してエンティティを分割することを優先できます。

エンティティの継承は、物事を正気に保つのに役立つ非常に強力なツールです。しかし、いつものように、継承を過剰に適用すると、狂気につながります。


代替案

これに対するもう1つのアプローチは、査読グループを派生させずに、学生と学生グループの間に基本クラスを提供することです。以下に沿ったもの:

public abstract class PeerReviewSubject
{
    public string Id { get; set; }
}

public class Student : PeerReviewSubject { }

public class StudentGroup : PeerReviewSubject { }

public class PeerReviewGroup : StudentGroup
{
    [ForeignKey("Subject")]
    public PeerReviewSubject Subject { get; set; }
    public string SubjectId { get; set; }
}

あなたが使用しているstring IDは好きではありませんが、それは別の戦いです。

これにより同じ結果が得られますが、新しいピアレビュー可能なエンティティタイプがドメインに追加されるたびにPeerReviewGroupを拡張し続ける必要はありません。代わりに、すべての新しいピアレビュー可能なエンティティタイプは単にPeerReviewSubjectから派生するため、ピアレビューグループに割り当てることができます。

例ではPeerReviewSubjectを抽象化しました。これは必須ではありませんが、それ以上の派生なしでベアボーンPeerReviewSubjectオブジェクトを作成したくない場合は、この方法が適しています。

1
Flater

この質問に答えるには、PeerReviewGroupのライフサイクルについて考える必要があります。

  • 作成時に常にどのようなグループであるかを知っていますか?
  • 同じグループが作成された後、その種類のレビュー対象を変更することは絶対に除外されますか?

両方の質問に対する答えが「はい」の場合、2つのクラスを作成することを検討できます。しかし、これは必ずしもそうすべきだという意味ではありません。

より基本的な質問は、PeerReviewGroupforIndividualsIS-Aが実際に特定のPeerReviewGroupであるかどうかであり、他とは非常に異なります(継承)または、それが単なるPeerReviewGroupである場合は、HAS-A異なるSubjectを調査(構成)するだけです。結局のところ、個人をレビューしているピアレビューグループほど、グループをレビューしているピアレビューに近いものはありません。同じグループで両方を行うこともできます。

2つの選択肢の境界は、あいまいになる可能性があります。疑問がある場合:

優先 継承よりも構成

1
Christophe