我正在使用 SQLite (v1.0.88.0) 和 Dapper 通过附加的闭包表来存储一些分层数据。我foreign_keys
在 SQLite 中启用了支持,但它对我来说根本不起作用。
这是演示我的几个问题的最小示例代码:
using System.Data.SQLite;
using System.IO;
using Dapper;
class Program {
static string db = "test.db";
static void Main(string[] args) {
if(!File.Exists(db))
SQLiteConnection.CreateFile(db);
using(SQLiteConnection c = new SQLiteConnection("Data Source=" + db)) {
string initializationQuery =
"PRAGMA foreign_keys = ON;" + // enable FK
"DROP TABLE IF EXISTS Departments;" +
"DROP TABLE IF EXISTS Departments_treePath;" +
"CREATE TABLE IF NOT EXISTS Departments (ID INTEGER PRIMARY KEY AUTOINCREMENT, Name TEXT);" +
"CREATE TABLE IF NOT EXISTS Departments_treePath (ancestor INTEGER, descendant INTEGER, level INTEGER, " +
"PRIMARY KEY (ancestor, descendant)," +
"CONSTRAINT ancestor_ref FOREIGN KEY(ancestor) REFERENCES Departments(ID) ON DELETE CASCADE," +
"CONSTRAINT descendant_ref FOREIGN KEY(descendant) REFERENCES Departments(ID) ON DELETE CASCADE);";
c.Execute(initializationQuery);
long idA = AddNode(c, 0, "A"); // ID=1
long idB = AddNode(c, idA, "B"); // ID=2
long idC = AddNode(c, idB, "C"); // ID=3
// 1) It works , but it should not, because there is no ID=7 (FK fails)
c.Execute("INSERT INTO Departments_treePath (ancestor,descendant) VALUES (7,7)");
// 2) It works, but as far as i can see from SQLite DataBase Browser it does not delete all the references within the Departments_treePath table (cascade delete fails)
c.Execute("DELETE FROM Departments WHERE ID=@id;", new { id = idC });
}
}
static long AddNode(SQLiteConnection c, long ancestorID, string name) {
string query = "BEGIN;" +
"INSERT OR ROLLBACK INTO Departments (Name) VALUES(@Name);" +
"CREATE TEMP TABLE _ID AS SELECT last_insert_rowid() AS id;" +
"INSERT INTO Departments_treePath (ancestor, descendant, level) " +
"SELECT t.ancestor, (SELECT id FROM _ID), t.level + 1 FROM Departments_treePath AS t " +
"WHERE t.descendant = @ancestor " +
"UNION ALL SELECT id , id, 0 FROM _ID;" +
"SELECT id FROM _ID; DROP TABLE _ID;" +
"END;";
return System.Linq.Enumerable.First(c.Query<long>(query, new { ancestor = ancestorID, Name = name }));
}
}
我是 SQL/SQLite 的新手,我似乎遗漏了一些东西。请指导我。