没有所需的类 - 表结构与实体框架

时间:2013-03-25 21:22:46

标签: c# entity-framework ef-code-first ef-database-first

以下是我的问题的简化版本。想想调查应用程序:

  • 有问题,
  • 一个问题有很多选项,一个选项只能属于一个问题
  • 一个问题应该有一个类别,一个类别可以属于许多问题
  • 问题可能有很多标签,标签可能属于很多问题

此外,我想在问题和其他问题的选项之间定义依赖关系,这样如果用户选择了“你有车吗?”的“否”选项。问题,他/她不会被问到'你的车的品牌是什么?'。

Code First创建的自动生成的数据库模式和数据库首先创建的自动生成的代码都不令人满意。下面是为这两种方法生成的代码和数据库模式。

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 - Tables

Db First - Tables

Db First - Tables

Db First - Code

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; }
}

2 个答案:

答案 0 :(得分:0)

我不确定我是否理解它,但我认为你需要{并且已经拥有} many-to-many Option/Question - 此外,你还有一对一他们之间的许多(所有者)关系。

我不太了解这是否是最好的解决方案 - 但是要接受你的同意,让'依赖'关系(和另一个)...

...为此,您需要“微调”您的关系和索引表。 EF / CF在后台创建默认值,我认为你需要的是在流畅的配置中创建关系 - 并自己添加额外的列。

  

我通常建议您自己配置   代码 - vs属性/默认代码 - 就像在任何复杂的场景中一样   为您提供更多选择和控制,减少错误等。在我的   case,我只想知道为我创建了哪些表和列。

这是一个特定的示例代码(我删除了其他不必要的表,只需要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);

您可以并排定义两个单独的关系(一个一对多,另一个为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; }
}

<小时/> 对于更复杂的场景(使用多对多和手动定义流畅代码中的关系 - 我建议) - 看看我前面提到的这些详细示例 - 它具有您可能需要的大多数映射。

Many to many (join table) relationship with the same entity with codefirst or fluent API?

Code First Fluent API and Navigation Properties in a Join Table

EF code-first many-to-many with additional data

...如果你需要任何快速指针 - 让我知道问题 - 以及更多细节

答案 1 :(得分:0)

我的理解是你希望后续问题依赖于先前问题的答案......

我的建议是在问题和选项之间建立一个名为RequiredAnswer的关系表。这种关系将表示用户必须已经回答了一个或多个问题(由您自己实施)相关选项(您的图表不包括答案表)。然后由代码实现决定如何使用这种关系。