EF core 6.0 + SQLite外键约束,有意义的错误描述

Mar*_*ris 7 c# sqlite entity-framework-core

我试图涵盖一个大型项目,具有复杂的数据库模式和大量的集成测试。对于集成测试,我使用 SQLite 数据库。每次违反外键约束时,我都会收到错误:

FOREIGN KEY constraint failed
Run Code Online (Sandbox Code Playgroud)

堆:EntityFramework core 6.0, SQLite v 6.0

连接字符串: Data Source=:memory:;foreign keys=true

没有解释,它击中了哪个外键。在实体很复杂的情况下,总是需要异常多的时间来找出它是哪个约束。有什么方法可以使用有关外键约束已命中的信息来扩展异常吗?就像是:

FOREIGN KEY constraint - ItemId failed
Run Code Online (Sandbox Code Playgroud)

Mar*_*eld 3

当尝试使用冲突的外键进行提交时,SQLite 不会关闭事务。此时,您可以使用pragma命令来查询冲突外键的状态,修复或删除它们,然后继续提交事务。

然而,SQLite 的包装器通常会在出现错误时立即处理事务,从而导致该解决方案站不住脚。在这种情况下,您必须控制包装器提供的事务。

我们假设您了解如何管理 EFCore 中适合您的特定场景的事务(外部事务、跨上下文事务等)。此示例仅在单个上下文中使用事务。


using var context = new PersonContext();
using var transaction = context.Database.BeginTransaction();

try
{
  // set all foreign key enforcement to "DEFERRED"
  context.Database.ExecuteSql("PRAGMA defer_foreign_keys=1;");

  // various CRUD operations that may involve foreign key conflicts
  
    // read the foreign key information from the table-valued pragma functions
    // `foreign_key_check` and `foreign_key_list`
  string sql = @"select a.""table"" || '.'|| ""from"" from pragma_foreign_key_check a
                   inner join pragma_foreign_key_list(a.""table"") b on
                   b.id == a.fkid;";
                      
  var conflicts = context.Database
    .SqlQuery<string>(sql)
    .ToList();
        
    // the list will contains strings like "tableName.fkColumn"
    // handle conflicts if the list count > 0
    
    // go ahead and commit the transaction
  transaction.Commit();
}
catch (Exception)
{
  // TODO: Handle failure
}
Run Code Online (Sandbox Code Playgroud)

参阅
defer_foreign_keysforeign_key_checkforeign_key_list