C# 不能具有实体框架所需的类表结构

C# 不能具有实体框架所需的类表结构,c#,entity-framework,ef-code-first,ef-database-first,C#,Entity Framework,Ef Code First,Ef Database First,这是我问题的简化版本。考虑一个调查应用程序: 有问题, 一个问题有很多选项,一个选项只能属于一个问题 一个问题应该有一个类别,一个类别可以属于多个问题 一个问题可能有许多标记,一个标记可以属于许多问题 此外,我想定义一个问题和其他问题选项之间的依赖关系,这样,如果用户对“你有车吗?”问题投了“否”的票,他/她就不会被问到“你的车的品牌是什么?” 代码优先创建的自动生成数据库模式和数据库优先创建的自动生成代码都不令人满意。下面是为这两种方法生成的代码和db模式 EF可以按预期处理问题-标记关系

这是我问题的简化版本。考虑一个调查应用程序:

  • 有问题,
  • 一个问题有很多选项,一个选项只能属于一个问题
  • 一个问题应该有一个类别,一个类别可以属于多个问题
  • 一个问题可能有许多标记,一个标记可以属于许多问题
此外,我想定义一个问题和其他问题选项之间的依赖关系,这样,如果用户对“你有车吗?”问题投了“否”的票,他/她就不会被问到“你的车的品牌是什么?”

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

EF可以按预期处理问题-标记关系,但它不能处理问题和选项之间的依赖关系(正如我所理解的),因为问题已经有了自己的选项

就EF而言,这种情况下理想的代码/数据库设计是什么

代码优先-代码
公开课问题
{
公共长Id{get;set;}
公共字符串文本{get;set;}
公共虚拟ICollection标记{get;set;}
公共虚拟ICollection选项{get;set;}
公共虚拟ICollection DependencyOptions{get;set;}
[外国钥匙(“类别”)]
公共虚拟类别{get;set;}
公共长类别ID{get;set;}
}
公共类选项
{
公共长Id{get;set;}
公共字符串文本{get;set;}
公共虚拟ICollection依赖性问题{get;set;}
[外国钥匙(“问题ID”)]
公共虚拟问题{get;set;}
公共长问题ID{get;set;}
}
公共类标签
{
公共长Id{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection问题{get;set;}
}
公共类类别
{
公共长Id{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection问题{get;set;}
}
代码优先-表

数据库优先-表

数据库优先-代码
公开课问题
{    
公共长Id{get;set;}
公共字符串文本{get;set;}
公共长类别ID{get;set;}
公共虚拟类别{get;set;}
公共虚拟ICollection选项{get;set;}
公共虚拟ICollection选项1{get;set;}
公共虚拟ICollection标记{get;set;}
}
公共类选项
{    
公共长Id{get;set;}
公共字符串文本{get;set;}
公共长问题ID{get;set;}
公共虚拟问题{get;set;}
公共虚拟ICollection问题{get;set;}
}
公共类标签
{    
公共长Id{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection问题{get;set;}
}
公共类类别
{    
公共长Id{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection问题{get;set;}
}

我不确定我是否理解正确,但我认为您将需要(并且已经有)一个关于
选项/问题的
多对多
-另外,它们之间还存在一对多(所有者)关系

我不知道这是否是最好的解决方案,但相信你的话,这两种“依赖”关系(以及另一种)都存在

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

我通常会建议您在 代码-vs属性/默认值-在任何复杂场景中 为您提供更多的选择和控制,减少错误等 在这种情况下,我只想知道为我创建了哪些表和列

这里是一个特定的示例代码(我删除了其他不必要的表,只是Q/O)

您已经定义了两个独立的关系(一对多和其他m对m),并排定义

QuestionOption
表中,您现在可以手动指定您需要为依赖项添加的所有内容(这是您的依赖项选项-我只是认为这个命名更清楚)。因此,您可能会遇到类似于
问题(A)->允许选项(B)
——但考虑到您的逻辑,您可能需要添加更多

看起来您需要在
问题、问题、选项
-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; }
}
modelBuilder.Entity()
.HasKey(i=>new{i.OptionID,i.QuestionLeftID,i.QuestionRightID});
modelBuilder.Entity()
.HasRequired(i=>i.Opiton)
.具有多个(u=>u.Dependency选项)
.HasForeignKey(i=>i.OptionID)
.WillCascadeOnDelete(假);
modelBuilder.Entity()
.HasRequired(i=>i.left)
.具有多个(u=>u.Dependency选项左)
.HasForeignKey(i=>i.QuestionLeftID)
.WillCascadeOnDelete(假);
modelBuilder.Entity()
.HasRequired(i=>i.QuestionRight)
.具有多个(u=>u.DependencyOptionRight)
.HasForeignKey(i=>i.QuestionRightID)
.WillCascadeOnDelete(假);
modelBuilder.Entity()
.HasRequired(i=>i.Question)
.具有多个(u=>u.选项)
.HasForeignKey(i=>i.QuestionId)
.WillCascadeOnDelete(假);
公开课问题
{
公共长Id{get;set;}
公共字符串文本{get;set;}
公共虚拟ICollection选项{get;set;}
公共虚拟ICollection DependencyOptionsLeft{get;set;}
公共虚拟ICollection DependencyOptionRight{get;set;}
}
公共类问题选项
{
公共长问题leftID{get;set;}
公共问题QuestionLeft{get;set;}
公众长提问者
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; }
}
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);
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; }
}