C# EF中的复合密钥

C# EF中的复合密钥,c#,entity-framework,C#,Entity Framework,我似乎无法理解EF是如何处理复合键的。当我尝试“添加迁移初始值”时,下面的代码返回“属性'QuestionID'不能用作实体QuestionQuestionTypesModel'的键属性,因为该属性类型不是有效的键类型。仅支持标量类型、字符串和字节[]键类型。” 我还尝试设置注释,而不是重写ModelCreating。我使用了[Key,Column(Order=0)] 有人能给我一些关于我做错了什么的线索吗?或者解释发生了什么,以便更好地理解手头的问题 public clas

我似乎无法理解EF是如何处理复合键的。当我尝试“添加迁移初始值”时,下面的代码返回“属性'QuestionID'不能用作实体QuestionQuestionTypesModel'的键属性,因为该属性类型不是有效的键类型。仅支持标量类型、字符串和字节[]键类型。”

我还尝试设置注释,而不是重写ModelCreating。我使用了[Key,Column(Order=0)]

有人能给我一些关于我做错了什么的线索吗?或者解释发生了什么,以便更好地理解手头的问题

          public class QuestionModel
    {
        [Key]
        [HiddenInput(DisplayValue = false)]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public Guid ID { get; set; }

        [Required]
        [StringLength(250)]
        public string Question { get; set; }
   }


  public class QuestionTypeModel
    {
        [Key]
        [HiddenInput(DisplayValue = false)]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public Guid ID { get; set; }

        [Required]
        [StringLength(250)]
        public string TypeName { get; set; }
    }


  public class QuestionQuestionTypesModel
    {
        public virtual QuestionModel QuestionID {get;set;}
        public virtual QuestionTypeModel QuestionTypeID { get; set; }
    }

public class InnuendoContext : DbContext
    {

      public IContext() : base("DefaultConnection")
        {
        }

        public DbSet<QuestionTypeModel> QuestionTypes { get; set; }
        public DbSet<QuestionModel> Questions { get; set; }
        public DbSet<QuestionQuestionTypesModel> QuestionQuestionTypes { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
            modelBuilder.Entity<QuestionQuestionTypesModel>().HasKey(a => new { a.QuestionID, a.QuestionTypeID });
        }
}
公共类问题模型
{
[关键]
[HiddenInput(DisplayValue=false)]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
公共Guid ID{get;set;}
[必需]
[长度(250)]
公共字符串问题{get;set;}
}
公共类问题类型模型
{
[关键]
[HiddenInput(DisplayValue=false)]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
公共Guid ID{get;set;}
[必需]
[长度(250)]
公共字符串类型名{get;set;}
}
公共类问题类型模型
{
公共虚拟问题模型问题ID{get;set;}
公共虚拟QuestionTypeModel QuestionTypeID{get;set;}
}
公共类inneudocontext:DbContext
{
public IContext():基本(“默认连接”)
{
}
公共数据库集问题类型{get;set;}
公共数据库集问题{get;set;}
公共数据库集问题类型{get;set;}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
基于模型创建(modelBuilder);
modelBuilder.Conventions.Remove();
modelBuilder.Entity().HasKey(a=>new{a.QuestionID,a.QuestionTypeID});
}
}
modelBuilder.Entity().HasKey(a=>new{a.QuestionID,a.QuestionTypeID});
QuestionID和QuestionTypeID都是导航属性,因此不能用作主键。正如错误消息所表明的:只有这些数据类型被支持作为主键(可以转换为支持的数据库中的键列),不幸的是,QuestionModel和QuestionTypeModel都不是主键。
添加Guid键值以匹配QuestionModel和QuestionTypeModel的键列。

您必须创建表所需的属性,这些属性也是系统的外键。通过设置此结构:

public class QuestionQuestionTypesModel
{
    [Key, Column(Order = 1), ForeignKey("Question")]
    public Guid QuestionID { get; set; }
    [Key, Column(Order = 2), ForeignKey("QuestionType")]
    public Guid QuestionTypeID { get; set; }

    public virtual QuestionModel Question { get; set; }
    public virtual QuestionTypeModel QuestionType { get; set; }
}
您将获得以下迁移:

public override void Up()
{
    CreateTable(
        "dbo.QuestionModel",
        c => new
        {
            ID = c.Guid(nullable: false, identity: true),
            Question = c.String(nullable: false, maxLength: 250),
        })
        .PrimaryKey(t => t.ID);

    CreateTable(
        "dbo.QuestionTypeModel",
        c => new
        {
            ID = c.Guid(nullable: false, identity: true),
            TypeName = c.String(nullable: false, maxLength: 250),
        })
        .PrimaryKey(t => t.ID);

    CreateTable(
        "dbo.QuestionQuestionTypesModel",
        c => new
            {
                QuestionID = c.Guid(nullable: false),
                QuestionTypeID = c.Guid(nullable: false),
            })
        .PrimaryKey(t => new { t.QuestionID, t.QuestionTypeID })
        .ForeignKey("dbo.QuestionModel", t => t.QuestionID, cascadeDelete: true)
        .ForeignKey("dbo.QuestionTypeModel", t => t.QuestionTypeID, cascadeDelete: true)
        .Index(t => t.QuestionID)
        .Index(t => t.QuestionTypeID);
}
更新 刚刚看到你的评论。如果您只有多对多关系,并且不需要任何其他属性,则可以执行以下操作:

public class QuestionModel
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public Guid ID { get; set; }

    [Required]
    [StringLength(250)]
    public string Question { get; set; }
    //One question has many QuestionTypes
    public virtual ICollection<QuestionTypeModel> QuestionTypes { get; set; }
}


public class QuestionTypeModel
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public Guid ID { get; set; }

    [Required]
    [StringLength(250)]
    public string TypeName { get; set; }
    //One QuestionType has many Questions
    public virtual ICollection<QuestionModel> Questions { get; set; }
}
公共类问题模型
{
[关键]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
公共Guid ID{get;set;}
[必需]
[长度(250)]
公共字符串问题{get;set;}
//一个问题有许多问题类型
公共虚拟ICollection问题类型{get;set;}
}
公共类问题类型模型
{
[关键]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
公共Guid ID{get;set;}
[必需]
[长度(250)]
公共字符串类型名{get;set;}
//一个问题类型有很多问题
公共虚拟ICollection问题{get;set;}
}

这将产生相同的迁移,但使您的数据层更加清晰。

CModel
A
B
是什么?它们是表A和表B的外键。此示例代码无法编译<代码>A和
B
没有定义,除非您说出它们的确切含义。请用工作代码更新您的示例。如果没有,我将要求结束这个问题。我仍然不明白为什么前面的代码无法编译。无论如何,我更新了代码。希望现在更清楚了。你没有包括A类和B类,只有AModel和B类。这解释了很多。非常感谢。您的代码和解释非常清楚,谢谢!
public class QuestionModel
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public Guid ID { get; set; }

    [Required]
    [StringLength(250)]
    public string Question { get; set; }
    //One question has many QuestionTypes
    public virtual ICollection<QuestionTypeModel> QuestionTypes { get; set; }
}


public class QuestionTypeModel
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public Guid ID { get; set; }

    [Required]
    [StringLength(250)]
    public string TypeName { get; set; }
    //One QuestionType has many Questions
    public virtual ICollection<QuestionModel> Questions { get; set; }
}