在 SQLite 中启用外键约束

Posted

技术标签:

【中文标题】在 SQLite 中启用外键约束【英文标题】:Enabling Foreign key constraints in SQLite 【发布时间】:2011-05-14 08:28:20 【问题描述】:

我在 C# 中使用 SQLite,并且定义了一些带有外键的表。

现在,我知道在 SQLite 中默认情况下不强制执行外键约束,但我想将它们打开。

是否可以通过代码做到这一点?我查找了相关的question,但我不确定如何通过 C# 代码来实现。我正在使用可用于 Visual Studio 2008 的最新 SQLite 插件来设计我的表。

conn.Open();
SQLiteCommand cmd = new SQLiteCommand("PRAGMA foreign_keys = ON", conn);
cmd.ExecuteNonQuery(); 
conn.Close();

重新打开此连接后,我需要保持此更改。有可能吗?

【问题讨论】:

【参考方案1】:

终于从this post 弄明白了。 PRAGMA foreign_key 设置不会保留,但您可以在每次在 ConnectionString 中建立连接时设置它。这允许您使用 Visual Studio 的表适配器。

    确保您已安装 system.data.sqlite 的 latest version (1.0.73.0)(1.0.66.0 将无法工作)。 将您的 ConnectionString 更改为 data source=C:\Dbs\myDb.db;foreign keys=true;(将 C:\Dbs\myDb.db 替换为您的 sqlite 数据库)。

【讨论】:

当时我使用的是 1.0.66.0 版本。我在没有外键功能的情况下继续前进。很高兴知道这个问题终于解决了。我会在以后的工作中记住这一点。谢谢 我尝试了这篇文章中提到的所有其他方法,但只有这个对我有用。 令我震惊的是,在 2020 年 SQLite 仍然禁用外键约束,即使在明确启用它们之后!谈论主要的数据损坏。【参考方案2】:

打开编译指示:

PRAGMA foreign_keys = ON;

您可以像执行任何其他 SQL 语句一样执行它。

【讨论】:

我正在使用 SqliteDataAdapter,它管理连接的打开和关闭。我相信当连接关闭时,这些信息就会丢失。我怎样才能使这些信息持久存在? @kaustubh:你是对的,foreign_key pragma 是 session-local。我不知道 SqliteDataAdapter 是如何工作的,但它似乎在其构造函数中采用了 SQLConnection 参数。您可以在创建连接时针对连接发出编译指示吗? 似乎没有办法在连接字符串中指定此信息。有没有办法指定每次打开连接时执行的命令? @kaustubh:我的意思是你应该创建一个 SQLiteConnection,在其上调用 pragma 语句,然后使用该连接构造 SQLiteDataAdapter。【参考方案3】:

我也在这个问题上苦苦挣扎。我决定在连接数据库时调查SQLDriverConnect() 中生成的完整连接字符串。这是它返回的内容:

'Driver=SQLite3 ODBC Driver;Database=C:\Users\Staples\Documents\SQLLiteTest.s3db;StepAPI=;SyncPragma=;NoTXN=;Timeout=;ShortNames=;LongNames=;NoCreat=;NoWCHAR=;FKSupport=;JournalMode=;OEMCP=;LoadExt=;BigInt=;PWD='

如您所见,有一个FKSupport 属性。 将FKSupport=True; 添加到我的连接字符串后,它返回:

'Driver=SQLite3 ODBCDriver;Database=C:\Users\Staples\Documents\SQLLiteTest.s3db;StepAPI=;SyncPragma=;NoTXN=;Timeout=;ShortNames=;LongNames=;NoCreat=;NoWCHAR=;FKSupport=True;JournalMode=;OEMCP=;LoadExt=;BigInt=;PWD='

瞧!强制执行外键约束。

【讨论】:

【参考方案4】:

另一种解决方案是对每个查询执行“PRAGMA foreign_keys=ON”。

SQLiteConnection connection = new SQLiteConnection("Data Source=" + dbSQLite + ";Read Only=False;"); 连接.打开(); SQLiteCommand mycommand = new SQLiteCommand(connection); mycommand.CommandText = "PRAGMA foreign_keys=ON"; mycommand.ExecuteNonQuery(); mycommand.CommandText = "从表中删除 ID=x"; mycommand.ExecuteReader(); 连接。关闭();

如果你把它放在你传递 CommandText 的函数中,你可以重复使用它。

【讨论】:

【参考方案5】:

这些应该提供您正在寻找的信息:

http://www.sqlite.org/faq.html#q22

http://www.sqlite.org/foreignkeys.html#fk_enable

简而言之,3.6.19 之前的版本根本不强制执行外键,但可以使用触发器来模拟它们;从 3.6.19 开始,可以强制执行外键,但这需要使用 PRAGMA foreign_keys = ON 语句为每个连接启用,并且 sqlite 必须在启用触发器和外键支持的情况下编译(我希望是这种情况任何二进制分布)。

【讨论】:

我正在使用自动管理连接打开和关闭的 SqliteDataAdapter。每次进行更新时,我该如何执行此 PRAGMA?【参考方案6】:

添加到您的连接字符串:";EnforceFKConstraints=Yes|True|1;"

【讨论】:

看到你的回复我欣喜若狂,这似乎是一个完美的解决方案。但唉,它不起作用:(也许 .NET 的 Sqlite 数据提供程序还不支持它。如果它确实如此,那么我无能为力了如何使它工作.. @kaustubh:尝试使用dbFacade。也许它支持? Author's blog 不幸的是俄语(他来自乌克兰,似乎是),但我可以帮你翻译 @kaustubh:顺便说一句,你添加了EnforceFKConstraints=YesEnforceFKConstraints=TrueEnforceFKConstraints=1。还是一次性全部?【参考方案7】:

看起来您可以像执行 Select 或 Update 语句一样在数据库连接上执行 SQL 命令 PRAGMA foreign_keys = ON;。尽管您必须确保您的 SQLite 是使用外键等编译的。见Here。

【讨论】:

【参考方案8】:
In C++ store app the following code helped me to enable PRAGMA foreign_keys
sqlite3_stmt* stmt;
sqlite3_prepare(db, "PRAGMA foreign_keys = ON;", -1, &stmt, 0); 
sqlite3_step(stmt);

I called this after creating db using the call of 

int rc = sqlite3_open16(path->Data(), &db);

【讨论】:

以上是关于在 SQLite 中启用外键约束的主要内容,如果未能解决你的问题,请参考以下文章

外键约束问题(分层数据)

如何向现有 SQLite 表添加外键?

如何通过 Java 在 SQLite 中强制执行外键约束?

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

oracle 删除外键约束 禁用约束 启用约束

Android中使用SQLite的外键约束?在删除级联