43

I'm using SQLite with C# and have some tables with foreign keys defined.

Now, I know that by default foreign key constraints are not enforced in SQLite, but I'd like to turn them ON.

Is it possible to do this through code? I have looked up a related question, but I'm not sure how to do it through C# code. I'm using the latest plug-in of SQLite available for Visual Studio 2008 for designing my tables.

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

I need this change to persist when this connection is reopened. Is it possible?

8 Answers 8

73

Finally figured this out from this post. The PRAGMA foreign_key setting does not persist but you can set it every time the connection is made in the ConnectionString. This allows you to use Visual Studio's table adapters.

  1. Make sure you have the latest version (1.0.73.0) of system.data.sqlite installed (1.0.66.0 will not work).
  2. Change your ConnectionString to data source=C:\Dbs\myDb.db;foreign keys=true; (replace C:\Dbs\myDb.db with your sqlite database).
Sign up to request clarification or add additional context in comments.

3 Comments

I was using version 1.0.66.0 then. I went ahead without the foreign key feature. Its nice to know that this issue is finally resolved. I'll keep it in mind for any future work. Thanx
I tried all other methods mentioned in this post, and only this one worked for me.
I am shocked that in 2020 SQLite still disables foreign key constraints, even after explicitly enabling them! Talk about major data corruption.
9

Turn on the pragma:

PRAGMA foreign_keys = ON;

You can execute this just like any other SQL statement.

4 Comments

I'm using SqliteDataAdapter, it manages opening and closing of connections. I believe when a connection is closed, this information is lost. How can I make this information persist?
@kaustubh: You are right, the foreign_key pragma is session-local. I don't know how SqliteDataAdapter works, but it seems to take a SQLConnection parameter in its constructor. Could you issue the pragma against the connection when you create it?
There doesn't seem to be a way to specify this information in connection string. Is there some way to specify a command that is executed each time a connection is opened?
@kaustubh: I meant that you should create a SQLiteConnection, invoke the pragma statement on it, and then use the connection to construct the SQLiteDataAdapter.
5

I too struggled with this issue. I decided to investigate the full connection string generated in SQLDriverConnect() when connecting to the database. This is what it returned:

'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='

As you can see there is a FKSupport property. After adding FKSupport=True; to my connection string it returned this:

'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='

And voila! foreign key contraints are enforced.

Comments

3

Another solution is to do the "PRAGMA foreign_keys=ON" with every query.

    SQLiteConnection connection = new SQLiteConnection("Data Source=" + dbSQLite + ";Read Only=False;");
    connection.Open();
    SQLiteCommand mycommand = new SQLiteCommand(connection);
    mycommand.CommandText = "PRAGMA foreign_keys=ON";
    mycommand.ExecuteNonQuery();
    mycommand.CommandText = "DELETE FROM table WHERE ID=x";
    mycommand.ExecuteReader();
    connection.Close();

If you put it in a function to which you pass the CommandText you can reuse it.

Comments

2

These should provide the information you're looking for:

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

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

In short, versions before 3.6.19 don't enforce foreign keys at all, but they can be simulated using triggers; starting with 3.6.19, foreign keys can be enforced, but this needs to be enabled per connection using the PRAGMA foreign_keys = ON statement, and sqlite must be compiled with trigger and foreign key support enabled (which I'd expect to be the case for any binary distribution).

1 Comment

I'm using SqliteDataAdapter which manages opening and closing of connections automatically. How do I, then enforce this PRAGMA each time an Update is made?
1

Add to your connection string: ";EnforceFKConstraints=Yes|True|1;"

3 Comments

I was euphoric on seeing your reply, seemed like the perfect solution.. But alas, it doesn't work :( Maybe Sqlite data provider for .NET doesn't support it yet.. If it does, then I'm at my wit's end how to make it work..
@kaustubh: Try to use dbFacade. Maybe it supports that? Author's blog unfortunately is in Russian (he is from Ukraine, seems to be), but I can try to help you to translate
@kaustubh: btw, have you added EnforceFKConstraints=Yes or EnforceFKConstraints=True or EnforceFKConstraints=1. Or all of them at once?
0

Looks like you can just execute the SQL command PRAGMA foreign_keys = ON; on your DB connection just like you would a Select or an Update statement. Though you have to make sure your SQLite was compiled with foreign keys and such. See Here.

Comments

-2
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);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.