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