簡體   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