SQLite EF Core - '外键约束失败'

Posted

技术标签:

【中文标题】SQLite EF Core - \'外键约束失败\'【英文标题】:SQLite EF Core - 'FOREIGN KEY constraint failed'SQLite EF Core - '外键约束失败' 【发布时间】:2020-10-18 21:39:26 【问题描述】:

在我的 ASP.Net Core 项目中,我在启动时遇到了这个异常,因为我在运行时初始化数据库:

失败:Microsoft.EntityFrameworkCore.Update[10000]

保存上下文类型“BlazorWeb.Server.Data.SQLiteTestDbContext”的更改时,数据库中发生异常。 Microsoft.EntityFrameworkCore.DbUpdateException:更新条目时出错。有关详细信息,请参阅内部异常。

Microsoft.Data.Sqlite.SqliteException (0x80004005):SQLite 错误 19:“FOREIGN KEY 约束失败”。

在 Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db) ....

我的模型:

public class ObjectModel : BaseEntity

    [Key]
    public int Id  get; set; 
    public String Name  get; set; 
    public String PreviewImage  get; set; 
    public String  TagName  get; set; 

    // Foreign keys---
    public int TypeId  get; set; 
    public ObjectTypeModel TypeModel  get; set; 
    //---


public class ObjectTypeModel : BaseEntity

    [Key]
    public int TypeId  get; set; 
    public String Name  get; set; 
    public String PreviewImage  get; set; 
    public String TagName  get; set; 

    public ICollection<ObjectModel> Objects  get; set; 

DbContext中的My SQLite OnModelCreating方法:

protected override void OnModelCreating(ModelBuilder modelBuilder)

    modelBuilder.Entity<ObjectModel>()
      .HasOne<ObjectTypeModel>(d => d.TypeModel)
      .WithMany(dm => dm.Objects)
      .HasForeignKey(dkey => dkey.TypeId);

来自自动生成的迁移类:

            name: "Objects",
            columns: table => new
            
                Id = table.Column<int>(nullable: false)
                    .Annotation("Sqlite:Autoincrement", true),
                CreatedOn = table.Column<DateTime>(nullable: false),
                ModifiedOn = table.Column<DateTime>(nullable: false),
                Name = table.Column<string>(nullable: true),
                PreviewImage = table.Column<string>(nullable: true),
                TagName = table.Column<string>(nullable: true),
                TypeId = table.Column<int>(nullable: false)
            ,
            constraints: table =>
            
                table.PrimaryKey("PK_Objects", x => x.Id);
                table.ForeignKey(
                    name: "FK_Objects_ObjectTypes_TypeId",
                    column: x => x.TypeId,
                    principalTable: "ObjectTypes",
                    principalColumn: "TypeId",
                    onDelete: ReferentialAction.Cascade);
            );

在我的初始化方法中,我只是用一些数据填充它并将它们保存到上下文中。但是数据库永远不会收到这些记录,并且还会发生外键约束异常。

任何人都可以帮助我 - 我做错了什么吗?

编辑 我发现在 SaveChangeAsync() 方法运行后发生异常。 我重写的SaveChangesAsyn() 方法:

     public Task<int> SaveChangesAsync()
     
      var entries = ChangeTracker
            .Entries()
            .Where(e => e.Entity is BaseEntity && (
                    e.State == EntityState.Added ||
                    e.State == EntityState.Modified));

            foreach (var entityEntry in entries)
            
                // overwrite `ModifiedOn` value with current date.
                ((BaseEntity)entityEntry.Entity).ModifiedO=
                 DateTime.Now; 

                // set `CreatedOn` to current date if its not already set. 
                if (entityEntry.State == EntityState.Added)
                
                    ((BaseEntity)entityEntry.Entity).CreatedOn = DateTime.Now;
                
            
            return base.SaveChangesAsync();
        

【问题讨论】:

当您将ObjectModelpublic int TypeId get; set; 更改为public int TypeModelId get; set; 时会发生什么? @JKL 在ObjectType.cs 中将其更改为 TypeModelId,但没有任何改变。还进行了新的迁移和数据库更新。 【参考方案1】:

我在尝试删除与另一个对象具有一对多关系的记录时遇到了同样的错误。

问题是在 DataContext 中未定义级联删除,您可以将以下内容添加到 DataContext:

            
 modelbuilder.Entity<ObjectTypeModel>()
                .HasMany(dm => dm.Objects)
                .WithOne()
                .OnDelete(DeleteBehavior.Cascade);

【讨论】:

【参考方案2】:

您的模型和迁移已更正。主要原因是当SaveChangesAsyn

 TypeId = table.Column<int>(nullable: false)

从这里我们可以看到,FK(TypeId) 不能为空。所以你应该确认你的FK(ObjectTypeTypeId)不为空并且在你添加新对象时存在。

这是我添加对象的代码,模型和你一样。

public async Task<IActionResult> Create([Bind("Id,content,Deadline,IsComplete,UserId")] ToDoItem toDoItem)
        
            if (ModelState.IsValid)
            
                _context.Add(toDoItem);
                await _context.SaveChangesAsync();

            
            return View();
        

型号代码如下。

public class ToDoItem
    
        public int Id  get; set; 
        public string content  get; set; 
        public DateTime Deadline  get; set; 
        public bool IsComplete  get; set; 

        public int UserId  get; set; 
        public User user  get; set; 
    

public class User
    
        public int Id  get; set; 
        public string username  get; set; 
        public string password  get; set; 
        public ICollection<ToDoItem> ToDoItems  get; set; 
    

【讨论】:

以上是关于SQLite EF Core - '外键约束失败'的主要内容,如果未能解决你的问题,请参考以下文章

EF Core / Sqlite 一对多关系在唯一索引约束上失败

SQLite 错误 19:“外键约束失败”

Django 2.0:sqlite IntegrityError:外键约束失败

外键约束,带有子对象集合的 EF

Java JDBC PreparedStatement 外键约束失败

有啥方法可以获取由于执行单个语句而失败的特定外键约束?