繁体   English   中英

在 c# compact-framework 中,如何在保持开放连接中的外键约束的同时执行 SQLite 事务?

[英]In c# compact-framework, how do you do a SQLite transaction while keeping foreign key constraints in an open connection?

我正在 Windows Forms .Net Compact Framework 3.5 中创建一个带有 SQLite 数据库的应用程序。 出于性能原因,我需要保持与数据库的开放连接,并且我需要使用事务来执行多个更新以实现回滚的可能性。

在一些 SQLite 表中有外键约束,默认情况下外键强制是关闭的,所以我必须在打开从应用程序到数据库的连接时手动打开它们。

现在的问题是事务不允许外键约束:( https://sqlite.org/pragma.html#pragma_foreign_keys

因此,当我运行更新语句时,它们失败并且事务回滚。

我尝试在事务之前手动关闭外键约束,然后更新成功。 但是当我尝试在事务后重新打开外键约束时,更新失败。

我需要打开外键约束,但它们在事务期间失败,我不能简单地关闭它们,运行事务,然后再重新打开它们。 所以我该怎么做?

using (var cmd1 = new SQLiteCommand(Con))
{
    cmd1.CommandText = "PRAGMA foreign_keys = 0"; //turn foreign key contraint off before transaction
    cmd1.ExecuteNonQuery();                      
}

var cmd2 = new SQLiteCommand(Con);
using (SQLiteTransaction transaction = Con.BeginTransaction())
{
    //run update commands here

    transaction.Commit();                       //run transaction
}

using (var cmd3 = new SQLiteCommand(Con))
{
    cmd3.CommandText = "PRAGMA foreign_keys = 1"; //turn foreign key constraint back on after transaction
    cmd3.ExecuteNonQuery();                      //this doesnt work
}


您可以在事务期间启用外键。 您不能在交易期间打开或关闭它们 - 您必须在开始交易之前打开它们。

当您打开连接时打开 pragma 可能是最简单的 - 然后您可以忘记它。

这对我来说很好用:

// Con is a SQLite connection, that has been opened.    
using (var cmd = Con.CreateCommand())
{
    cmd.CommandText = "PRAGMA foreign_keys = ON";
    cmd.ExecuteNonQuery();
}

using (var cmd = Con.CreateCommand())
{
    cmd.CommandText = @"
    CREATE TABLE A(id integer not null primary key);
    CREATE TABLE B(id integer not null primary key, a_id integer, FOREIGN KEY(a_id) REFERENCES A(id))
    ";
    cmd.ExecuteNonQuery();
}

try
{
    using (var transaction = Con.BeginTransaction())
    {
        using (var cmd = Con.CreateCommand())
        {
            cmd.CommandText = "INSERT INTO A VALUES(1); INSERT INTO A VALUES(2); INSERT INTO B VALUES(1, NULL); INSERT INTO B VALUES(2, 1);";
            cmd.ExecuteNonQuery();
        }

        using (var cmd = Con.CreateCommand())
        {
            cmd.CommandText = "INSERT INTO B VALUES(3, 55);";
            cmd.ExecuteNonQuery();  //Will crash beceause of invalid reference
        }

        transaction.Commit();
    }
} catch(DbException) {
    // Ignore transaction failure in this example   
    if(!e.Message.Contains("foreign key constraint failed"))
        throw;
}

using (var cmd = Con.CreateCommand())
{
    // Validate that nothing was inserted in the failed transaction
    cmd.CommandText = "SELECT COUNT(*) FROM A";
    Debug.Assert((long)cmd.ExecuteScalar() == 0);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM