实体框架代码优先迁移忽略 [Key] 并强制复合键

Posted

技术标签:

【中文标题】实体框架代码优先迁移忽略 [Key] 并强制复合键【英文标题】:Entity Framework code-first migration ignoring [Key] and forcing composite key 【发布时间】:2022-01-12 02:28:44 【问题描述】:

我正在尝试使用 [Key] 创建具有 Guid 主键的对象,但 Entity Framework 不断强制创建复合键。

public class Challenge

    [Key] 
    public Guid Id  get; set; 

    public Guid ChallengerId  get; set; 
    public Guid ChallengeeId  get; set; 

    [ForeignKey("ChallengerId")]
    public virtual Player Challenger  get; set; 

    [ForeignKey("ChallengeeId")]
    public virtual Player Challengee  get; set; 

    public DateTime Initiated  get; set; 

及其迁移...

migrationBuilder.CreateTable(
                name: "Challenges",
                columns: table => new
                
                    ChallengerId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
                    ChallengeeId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
                    Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
                    Initiated = table.Column<DateTime>(type: "datetime2", nullable: false)
                ,
                constraints: table =>
                
                    table.PrimaryKey("PK_Challenges", x => new  x.ChallengerId, x.ChallengeeId );
                    table.ForeignKey(
                        name: "FK_Challenges_Players_ChallengeeId",
                        column: x => x.ChallengeeId,
                        principalTable: "Players",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Restrict);
                    table.ForeignKey(
                        name: "FK_Challenges_Players_ChallengerId",
                        column: x => x.ChallengerId,
                        principalTable: "Players",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Restrict);
                );

请注意,我使用相同的方法创建了 Player 类,并且 Entity Framework 尊重那里的 [Key] 属性。

public class Player

    [Key] 
    public Guid Id  get; set; 
    public string UserId  get; set; 
    [ForeignKey("UserId")]
    public virtual IdentityUser User  get; set; 
    
    public virtual ICollection<Game> Games  get; set; 
    [InverseProperty("Challenger")]
    public virtual ICollection<Challenge> OutgoingChallenges  get; set; 
    [InverseProperty("Challengee")]
    public virtual ICollection<Challenge> IncomingChallenges  get; set; 

migrationBuilder.CreateTable(
                name: "Players",
                columns: table => new
                
                    Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
                    UserId = table.Column<string>(type: "nvarchar(450)", nullable: false)
                ,
                constraints: table =>
                
                    table.PrimaryKey("PK_Players", x => x.Id);
                    table.ForeignKey(
                        name: "FK_Players_IdentityUser_UserId",
                        column: x => x.UserId,
                        principalTable: "IdentityUser",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Cascade);
                );

即使我进入迁移和改变

table.PrimaryKey("PK_Challenges", x => new  x.ChallengerId, x.ChallengeeId );

table.PrimaryKey("PK_Challenges", x => x.Id);

Entity Framework 似乎在苦苦挣扎,因为它使用复合键在 SQL 数据库中创建 Challenges

我正在使用 .NET 6。

【问题讨论】:

你有流畅的api吗? 我不确定?这是一个相当新的/稀疏的项目。为什么这会影响实体构建器? 【参考方案1】:

您的 Player 模型中可能缺少 [Key] 属性吗?

public class Player

    //Here should be a [Key] annotation
    public Guid Id  get; set; 
    public string UserId  get; set; 
    [ForeignKey("UserId")]
    public virtual IdentityUser User  get; set; 
    
    public virtual ICollection<Game> Games  get; set; 
    [InverseProperty("Challenger")]
    public virtual ICollection<Challenge> OutgoingChallenges  get; set; 
    [InverseProperty("Challengee")]
    public virtual ICollection<Challenge> IncomingChallenges  get; set; 

【讨论】:

看起来我是,尽管我的播放器模型的行为符合预期。这可能会阻止外键正确映射。让我看看,然后回复你。谢谢你的收获! 不是这样的。我会更新问题 - 玩家 ID 有 [Key]。此外,IIRC,它不应该需要它 - Id 约定应该默认为主键,对吧? 嗯,我认为你是对的。但是,通过自动迁移,两个版本都成功地创建了我的表和约束。【参考方案2】:

我找到了罪魁祸首:AppDbContext.cs

modelBuilder.Entity<Challenge>()
                    .HasForeignKey(c => new  c.ChallengerId, c.ChallengeeId );

【讨论】:

以上是关于实体框架代码优先迁移忽略 [Key] 并强制复合键的主要内容,如果未能解决你的问题,请参考以下文章

实体框架:如何从具有复合键的表中返回一行?

调试代码优先的实体框架迁移代码

实体框架代码优先主键约束名称

代码优先实体框架或 NHibernate

独立于模式的实体框架代码优先迁移

实体框架代码优先 - 初始代码迁移不起作用