Внешний ключ в Rust
Столбец с номером чужой строки можно закрепить ограничением внешнего ключа. Оно не дает записать номер, которого нет в родительской таблице, если движок действительно проверяет ссылку.
В SQLite проверку включают командой
PRAGMA foreign_keys = ON на
открытом соединении. Без нее вставка
с несуществующим номером может пройти
тихо, и связь в данных развалится.
Если проект еще без зависимости, из корня Cargo выполните:
cargo add rusqlite --features bundled
Создадим таблицы user и post
со ссылкой REFERENCES user(id):
use rusqlite::{Connection, params};
fn demo() -> Result<(), rusqlite::Error> {
let _ = std::fs::remove_file("app.db");
let conn = Connection::open("app.db")?;
conn.execute("PRAGMA foreign_keys = ON", [])?;
conn.execute(
"CREATE TABLE user (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
)",
[],
)?;
conn.execute(
"CREATE TABLE post (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
title TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES user(id)
)",
[],
)?;
conn.execute("INSERT INTO user (name) VALUES (?1)", params!["ann"])?;
conn.execute(
"INSERT INTO post (user_id, title) VALUES (?1, ?2)",
params![1, "note"],
)?;
Ok(())
}
fn main() {
match demo() {
Ok(()) => println!("ok"),
Err(e) => println!("{}", e),
}
}
На экране ok. Номер 1 в
user_id совпал с существующим
пользователем.
Попробуем записать пост с чужим номером:
use rusqlite::{Connection, params};
fn try_bad() -> Result<(), rusqlite::Error> {
let _ = std::fs::remove_file("app.db");
let conn = Connection::open("app.db")?;
conn.execute("PRAGMA foreign_keys = ON", [])?;
conn.execute(
"CREATE TABLE user (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
)",
[],
)?;
conn.execute(
"CREATE TABLE post (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
title TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES user(id)
)",
[],
)?;
match conn.execute(
"INSERT INTO post (user_id, title) VALUES (?1, ?2)",
params![99, "ghost"],
) {
Ok(_) => {
println!("saved");
Ok(())
}
Err(e) => {
println!("rejected");
Err(e)
}
}
}
fn main() {
let _ = try_bad();
}
Даны таблицы:
CREATE TABLE user (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE post (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
title TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES user(id)
);
INSERT INTO user (name) VALUES ('kim');
Включите проверку внешних ключей и
добавьте пост "box" для
пользователя с номером 1.
Выведите done при успехе.
Даны те же таблицы и включенная проверка.
Попробуйте вставить пост с user_id
50. При ошибке выведите bad id.
Скажите, зачем команду PRAGMA foreign_keys = ON
нужно выполнять на каждом новом открытии
app.db, а не один раз навсегда.