You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP Core添加一对一关系后EF Core迁移报错:SQLite非空约束失败

问题分析与解决方案

错误原因

  1. NOT NULL约束错误:SQLite在EF Core迁移过程中会通过临时表重写表结构,若原ContentPosts表已有数据,添加可空RatingId列后立即设置外键,EF Core的临时表处理逻辑可能错误地将RatingId视为非空字段,触发约束异常。
  2. 外键约束错误:设置默认值0L时,Ratings表为空,不存在Id=0的记录,违反外键引用规则,导致约束失败。
  3. 列未创建:迁移执行到外键步骤时失败回滚,导致之前的添加列操作未提交到数据库。

修复步骤

修改迁移的Up方法,调整操作顺序并处理现有数据,确保外键约束能正常创建:

protected override void Up(MigrationBuilder migrationBuilder)
{
    // 1. 先创建Ratings表,避免外键引用时目标表不存在
    migrationBuilder.CreateTable(
            name: "Ratings",
            columns: table => new
            {
                Id = table.Column<long>(type: "INTEGER", nullable: false)
                    .Annotation("Sqlite:Autoincrement", true),
                Commends = table.Column<long>(type: "INTEGER", nullable: false),
                Views = table.Column<long>(type: "INTEGER", nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Ratings", x => x.Id);
            });

    // 2. 添加ContentPosts的RatingId可空列
    migrationBuilder.AddColumn<long>(
            name: "RatingId",
            table: "ContentPosts",
            type: "INTEGER",
            nullable: true);

    // 3. 为现有ContentPosts生成对应的Ratings记录并关联(SQLite专用)
    migrationBuilder.Sql(@"
        -- 为每条ContentPosts创建初始Ratings数据
        INSERT INTO Ratings (Commends, Views)
        SELECT 0, 0 FROM ContentPosts;
        
        -- 关联ContentPosts和对应的Ratings
        UPDATE ContentPosts
        SET RatingId = (SELECT Id FROM Ratings WHERE ROWID = ContentPosts.ROWID);
    ");

    // 4. 创建唯一索引(一对一关系必须添加,确保一个Rating仅对应一个ContentPost)
    migrationBuilder.CreateIndex(
            name: "IX_ContentPosts_RatingId",
            table: "ContentPosts",
            column: "RatingId",
            unique: true);

    // 5. 将RatingId设为非空(可选,若需要严格一对一)
    migrationBuilder.AlterColumn<long>(
            name: "RatingId",
            table: "ContentPosts",
            type: "INTEGER",
            nullable: false,
            oldClrType: typeof(long),
            oldType: "INTEGER",
            oldNullable: true);

    // 6. 添加外键约束,使用级联删除更符合一对一关系逻辑
    migrationBuilder.AddForeignKey(
            name: "FK_ContentPosts_Ratings_RatingId",
            table: "ContentPosts",
            column: "RatingId",
            principalTable: "Ratings",
            principalColumn: "Id",
            onDelete: ReferentialAction.Cascade);
}

额外建议

确保EF Core模型的一对一关系配置正确,在DbContext的OnModelCreating方法中添加:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<ContentPost>()
        .HasOne(c => c.Rating)
        .WithOne(r => r.ContentPost)
        .HasForeignKey<ContentPost>(c => c.RatingId)
        .OnDelete(DeleteBehavior.Cascade);
}

这样后续生成的迁移会自动符合一对一关系的规范,减少手动调整迁移代码的需求。

内容的提问来源于stack exchange,提问作者Epic Gamer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 18:50:26