Внешний ключ SQLite в C#
Примеры раздела используют SQLite через пакет в файле проекта:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.14" />
</ItemGroup>
</Project>
Ограничение FOREIGN KEY задает ссылку
зависимой таблицы на первичный ключ родителя.
В SQLite проверка срабатывает только после PRAGMA foreign_keys = ON на соединении. Таблица складов и ячеек с явной ссылкой на родителя создается ниже. Затем вставляют склад "W1" и ячейку "A-01". Печатают, сколько строк добавила последняя вставка:
using Microsoft.Data.Sqlite;
string dbPath = "fk_bins.db";
if (File.Exists(dbPath))
{
File.Delete(dbPath);
}
using SqliteConnection db = new($"Data Source={dbPath}");
db.Open();
using (SqliteCommand pragma = db.CreateCommand())
{
pragma.CommandText = "PRAGMA foreign_keys = ON";
pragma.ExecuteNonQuery();
}
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = "CREATE TABLE IF NOT EXISTS warehouses (id INTEGER PRIMARY KEY, code TEXT NOT NULL)";
cmd.ExecuteNonQuery();
}
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = "CREATE TABLE IF NOT EXISTS bins (id INTEGER PRIMARY KEY, warehouse_id INTEGER NOT NULL, label TEXT NOT NULL, FOREIGN KEY (warehouse_id) REFERENCES warehouses (id))";
cmd.ExecuteNonQuery();
}
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = "INSERT INTO warehouses (code) VALUES ($p1)";
cmd.Parameters.AddWithValue("$p1", "W1");
cmd.ExecuteNonQuery();
}
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = "INSERT INTO bins (warehouse_id, label) VALUES ($p1, $p2)";
cmd.Parameters.AddWithValue("$p1", 1);
cmd.Parameters.AddWithValue("$p2", "A-01");
Console.WriteLine(cmd.ExecuteNonQuery()); // выведет 1
}
Число в "warehouse_id" должно совпадать с
существующим "id" склада. Иначе шаг вставки
приведет к исключению SqliteException.
Номер 99 ни одному складу не принадлежит,
исключение перехватывают и пишут в консоль
"rejected":
using Microsoft.Data.Sqlite;
string dbPath = "fk_bins.db";
if (File.Exists(dbPath))
{
File.Delete(dbPath);
}
using SqliteConnection db = new($"Data Source={dbPath}");
db.Open();
using (SqliteCommand pragma = db.CreateCommand())
{
pragma.CommandText = "PRAGMA foreign_keys = ON";
pragma.ExecuteNonQuery();
}
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = "CREATE TABLE IF NOT EXISTS warehouses (id INTEGER PRIMARY KEY, code TEXT NOT NULL)";
cmd.ExecuteNonQuery();
}
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = "CREATE TABLE IF NOT EXISTS bins (id INTEGER PRIMARY KEY, warehouse_id INTEGER NOT NULL, label TEXT NOT NULL, FOREIGN KEY (warehouse_id) REFERENCES warehouses (id))";
cmd.ExecuteNonQuery();
}
using (SqliteCommand cmd = db.CreateCommand())
{
cmd.CommandText = "INSERT INTO bins (warehouse_id, label) VALUES ($p1, $p2)";
cmd.Parameters.AddWithValue("$p1", 99);
cmd.Parameters.AddWithValue("$p2", "ghost");
try { cmd.ExecuteNonQuery(); }
catch (SqliteException) { Console.WriteLine("rejected"); } // выведет "rejected"
}
В новой базе "fk_docks.db" создайте причалы
и лодки: у каждой лодки должен быть существующий
причал. Добавьте причал "D-1" и лодку
"B-12", затем выведите метку лодки
из таблицы.
Попробуйте привязать лодку к несуществующему
причалу. Если операция не прошла, выведите
"bad link".