0

これが私の問題の簡略版です。調査アプリケーションを考えてみましょう:

  • 質問がありますが、
  • 質問には多くのオプションがあり、オプションは質問にのみ属することができます
  • 質問には 1 つのカテゴリが必要です。カテゴリは多くの質問に属することができます
  • 質問には多くのタグを付けることができ、タグは多くの質問に属することができます

さらに、質問と他の質問のオプションとの間の依存関係を定義したいと思います。たとえば、ユーザーが「車を持っていますか?」に対して「いいえ」のオプションに投票した場合などです。「あなたの車のブランドは何ですか?」と聞かれることはありません。

Code First によって作成された自動生成データベース スキーマとデータベース ファーストによって作成された自動生成コードの両方が満足できるものではありません。以下は、両方の方法で生成されたコードと db スキーマです。

EFは質問とタグの関係を期待どおりに処理できますが、質問にはすでに独自のオプションがあるため、質問とオプションの間の依存関係を処理できません(私が理解したように)。

EF に関して言えば、この場合の理想的なコード/データベース設計は何でしょうか?

コードファースト - コード

public class Question
{
    public long Id { get; set; }
    public string Text { get; set; }
    public virtual ICollection<Tag> Tags { get; set; }
    public virtual ICollection<Option> Options { get; set; }
    public virtual ICollection<Option> DependencyOptions { get; set; }

    [ForeignKey("CategoryId")]
    public virtual Category Category { get; set; }
    public long CategoryId { get; set; }
}

public class Option
{
    public long Id { get; set; }
    public string Text { get; set; }

    public virtual ICollection<Question> DependencyQuestions { get; set; }

    [ForeignKey("QuestionId")]
    public virtual Question Question { get; set; }
    public long QuestionId { get; set; }
}

public class Tag
{
    public long Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Question> Questions { get; set; }
}
public class Category
{
    public long Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Question> Questions { get; set; }
}

Code First - テーブル

Code First - テーブル

データベースファースト - テーブル

データベースファースト - テーブル

データベースファースト - コード

public class Question
{    
    public long Id { get; set; }
    public string Text { get; set; }
    public long CategoryId { get; set; }

    public virtual Category Category { get; set; }
    public virtual ICollection<Option> Options { get; set; }
    public virtual ICollection<Option> Options1 { get; set; }
    public virtual ICollection<Tag> Tags { get; set; }
}

public class Option
{    
    public long Id { get; set; }
    public string Text { get; set; }
    public long QuestionId { get; set; }

    public virtual Question Question { get; set; }
    public virtual ICollection<Question> Questions { get; set; }
}

public class Tag
{    
    public long Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Question> Questions { get; set; }
}

public class Category
{    
    public long Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Question> Questions { get; set; }
}
4

2 に答える 2

0

私がそれを正しく理解したかどうかはわかりませんが、on が必要になる (そして既に持っている) と思います。many-to-manyさらにOption/Question、それらの間には 1 対多 (所有者) の関係もあります。

それが最善の解決策であるかどうかを議論するのに十分なことはわかりませんが、「依存関係」の関係(および他の関係)の両方を持つというあなたの言葉を取ります...

...そのためには、関係とインデックス テーブルを「微調整」する必要があります。EF/CF はバックグラウンドでデフォルトのものを作成します。必要なのは、流暢な構成でリレーションを作成し、自分で列を追加することだと思います。

そして、一般的に、コードで独自の構成を行うことをお勧めします-vs属性/デフォルトの構成-より多くのオプションと制御を提供し、エラーを減らすなどの複雑なシナリオのように.私の場合、どのテーブルと列が作成されます。

そして、ここに特定のサンプルコードがあります(不要な他のテーブルを削除しました。Q/Oだけです)...

public class QuestionContext : DbContext
{
    public DbSet<Question> Questions { get; set; }
    public DbSet<Option> Options { get; set; }
    public DbSet<QuestionOption> QuestionOptions { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<QuestionOption>()
            .HasKey(i => new { i.OptionID, i.QuestionID });

        modelBuilder.Entity<QuestionOption>()
            .HasRequired(i => i.Opiton)
            .WithMany(u => u.DependencyOptions)
            .HasForeignKey(i => i.OptionID)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<QuestionOption>()
            .HasRequired(i => i.Question)
            .WithMany(u => u.DependencyOptions)
            .HasForeignKey(i => i.QuestionID)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Option>()
            .HasRequired(i => i.Question)
            .WithMany(u => u.Options)
            .HasForeignKey(i => i.QuestionId)
            .WillCascadeOnDelete(false);
    }
}
public class Question
{
    public long Id { get; set; }
    public string Text { get; set; }
    public virtual ICollection<Option> Options { get; set; }
    public virtual ICollection<QuestionOption> DependencyOptions { get; set; }
}
public class Option
{
    public long Id { get; set; }
    public string Text { get; set; }
    // [ForeignKey("QuestionId")]
    public virtual Question Question { get; set; }
    public long QuestionId { get; set; }
    public virtual ICollection<QuestionOption> DependencyOptions { get; set; }
}
public class QuestionOption
{
    public long OptionID { get; set; }
    public Option Opiton { get; set; }
    public long QuestionID { get; set; }
    public Question Question { get; set; }
    public int DependencyType { get; set; }
    public string DependencyNote { get; set; }
    public bool Active { get; set; }
    public bool UseEtc { get; set; }
}

次の移行では...

        CreateTable(
            "dbo.Questions",
            c => new
                {
                    Id = c.Long(nullable: false, identity: true),
                    Text = c.String(maxLength: 4000),
                })
            .PrimaryKey(t => t.Id);

        CreateTable(
            "dbo.Options",
            c => new
                {
                    Id = c.Long(nullable: false, identity: true),
                    Text = c.String(maxLength: 4000),
                    QuestionId = c.Long(nullable: false),
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.Questions", t => t.QuestionId)
            .Index(t => t.QuestionId);

        CreateTable(
            "dbo.QuestionOptions",
            c => new
                {
                    OptionID = c.Long(nullable: false),
                    QuestionID = c.Long(nullable: false),
                    DependencyType = c.Int(nullable: false),
                    DependencyNote = c.String(maxLength: 4000),
                    Active = c.Boolean(nullable: false),
                    UseEtc = c.Boolean(nullable: false),
                })
            .PrimaryKey(t => new { t.OptionID, t.QuestionID })
            .ForeignKey("dbo.Options", t => t.OptionID)
            .ForeignKey("dbo.Questions", t => t.QuestionID)
            .Index(t => t.OptionID)
            .Index(t => t.QuestionID);

2 つの別個のリレーションシップ (1 対多と他の m 対 m) が並んで定義されています。

テーブル内QuestionOptionで、依存関係に追加する必要があるすべてを手動で指定できるようになりました (それが DependencyOption です。この命名により、より明確になると思いました)。したがって、次のようなものQuestion(A) -> allows Option(B)がありますが、ロジックを考えると、さらに追加する必要がある場合があります。

間に関係を確立する必要があるようですQuestion, Question, Option-つまり、3つのインデックスなど.上記のコードを考えると、必要に応じて単純な拡張だけでそれを行うことができます.

modelBuilder.Entity<QuestionOption>()
    .HasKey(i => new { i.OptionID, i.QuestionLeftID, i.QuestionRightID });
modelBuilder.Entity<QuestionOption>()
    .HasRequired(i => i.Opiton)
    .WithMany(u => u.DependencyOptions)
    .HasForeignKey(i => i.OptionID)
    .WillCascadeOnDelete(false);
modelBuilder.Entity<QuestionOption>()
    .HasRequired(i => i.QuestionLeft)
    .WithMany(u => u.DependencyOptionsLeft)
    .HasForeignKey(i => i.QuestionLeftID)
    .WillCascadeOnDelete(false);
modelBuilder.Entity<QuestionOption>()
    .HasRequired(i => i.QuestionRight)
    .WithMany(u => u.DependencyOptionsRight)
    .HasForeignKey(i => i.QuestionRightID)
    .WillCascadeOnDelete(false);
modelBuilder.Entity<Option>()
    .HasRequired(i => i.Question)
    .WithMany(u => u.Options)
    .HasForeignKey(i => i.QuestionId)
    .WillCascadeOnDelete(false);
public class Question
{
    public long Id { get; set; }
    public string Text { get; set; }
    public virtual ICollection<Option> Options { get; set; }
    public virtual ICollection<QuestionOption> DependencyOptionsLeft { get; set; }
    public virtual ICollection<QuestionOption> DependencyOptionsRight { get; set; }
}
public class QuestionOption
{
    public long QuestionLeftID { get; set; }
    public Question QuestionLeft { get; set; }
    public long QuestionRightID { get; set; }
    public Question QuestionRight { get; set; }
    public long OptionID { get; set; }
    public Option Opiton { get; set; }
    public int DependencyType { get; set; }
    public string DependencyNote { get; set; }
    public bool Active { get; set; }
    public bool AllowForbid { get; set; }
}


より複雑なシナリオ (流暢なコードで多対多および手動で関係を定義することをお勧めします) については、私が少し前に作成したこれらの詳細な例を見てください。必要なマッピングのほとんどが含まれています。

コードファーストまたは流暢な API を使用した同じエンティティとの多対多 (結合テーブル) の関係?

結合テーブルの Code First Fluent API とナビゲーション プロパティ

追加データを使用した EF コードファーストの多対多

...簡単なポインタが必要な場合は、質問でお知らせください-および詳細

于 2013-03-25T22:19:55.550 に答える
0

私の理解では、後続の質問が前の質問への回答に依存することを望んでいます...

私の提案は、RequiredAnswer のようなものと呼ばれる、質問とオプションの間の関係テーブルを持つことです。この関係は、ユーザーが関連するオプションの 1 つまたはすべて (実装はあなた次第) を使用して質問に回答した必要があることを示します (図には回答テーブルが含まれていません)。次に、この関係をどのように使用するかは、コードの実装次第です。

于 2013-03-25T22:58:00.343 に答える