SQLite / دليل حلول تحريري
تشخيص فشل العلاقة الخارجية وغياب فرضها
حدد إعلان العلاقة وفرضها وصحة مفتاحها وبياناتها قبل تغيير المخطط أو إخفاء فشل القيد.
قاعدة معرفة للقراءة فقط · بلا تعليقات عامة
تعرّف على الأعراض
قد يفشل الإدراج أو التحديث أو الحذف أو التثبيت برسالة FOREIGN KEY constraint failed، وقد يبدو أن تطبيقاً آخر يقبل صفاً يتيماً يرفضه هذا الاتصال.
تشير foreign key mismatch إلى شروط تعريف العلاقة، ولا تعني مجرد غياب صف أب. افحص العملية والرسالة بدقة قبل افتراض إصلاح موحد.
افهم الأسباب المحتملة
- قد يختلف الفرض بين الاتصالات أو يغيب الأب أو يخالف مفتاحه التفرد وترتيب المحارف أو يمنع الأبناء الحذف.
- قد لا يؤثر تغيير الإعداد داخل معاملة نشطة. وقد تؤجل العلاقة فشلها إلى حد لاحق، لذلك تهم ملكية المعاملة لا سطر الإدراج وحده.
افحص سياسة الاتصال الفعلية
افحص PRAGMA foreign_keys في الاتصال الذي ينفذ العمل وقبل المعاملة المطلوبة. لا تستنتج السياسة من صدفة أو إطار آخر. سجل الإصدار ونسخة المخطط وتعريف العلاقة وحالة المعاملة. يختلف إعلان FOREIGN KEY عن فرضه فعلياً، ولا يصلح تعطيله سجلات خاطئة؛ بل قد يؤجل اكتشافها ويزيد صعوبة المصالحة لاحقاً.
قارن بنية المفتاح ووجود الأب
تحقق من أعمدة الأب وتفردها ومقارنة محارفها، وافحص قيمة الابن بمعلمات ووحدة علاقة مقصودة. تختلف NULL الاختيارية عن معرف مطلوب مجهول، وتحتاج الحالة المطلوبة NOT NULL. عند الحذف راجع RESTRICT أوSET NULL أوCASCADE والاحتفاظ؛ ولا تختَر ما يسكت الرسالة فقط، لأن الأثر قد يمتد إلى بيانات تابعة كثيرة.
اختبر الرفض والإصلاح في الذاكرة
يفعل البرنامج الفرض صراحة ويرفض الإشارة إلى الأب9، ثم ينشئ أباً وطفلاً صحيحين. يعرض هوية الرفض وصفر مخالفات نهائية. يقع العمل في :memory: جديدة مغلقة عند المالك. لا يأذن المثال بإنشاء أب مختلق في بيانات فعلية؛ بل يجب إثبات الكيان من دليل المجال الصحيح قبل استخدامه لربط سجل تابع.
import sqlite3
from contextlib import closing
with closing(sqlite3.connect(":memory:", isolation_level=None)) as db:
db.execute("PRAGMA foreign_keys=ON")
db.executescript("CREATE TABLE parent(id INTEGER PRIMARY KEY); CREATE TABLE child(id INTEGER PRIMARY KEY,parent_id INTEGER NOT NULL REFERENCES parent(id));")
print("enforced", db.execute("PRAGMA foreign_keys").fetchone()[0])
try:
db.execute("INSERT INTO child VALUES(1,9)")
except sqlite3.IntegrityError as error:
print("rejected", error.sqlite_errorname)
else:
raise AssertionError("expected relationship rejection")
db.execute("INSERT INTO parent VALUES(9)")
db.execute("INSERT INTO child VALUES(1,9)")
print("violations", len(db.execute("PRAGMA foreign_key_check").fetchall()))
enforced 1
rejected SQLITE_CONSTRAINT_FOREIGNKEY
violations 0
يفشل الإدراج الخاطئ ويسمح أب التدريب المنشأ صراحة بالعلاقة الصحيحة.
أصلح البيانات أو المخطط عند مالكه
اختر إصلاحاً يثبته الدليل: صحح مفتاح الابن أو أنشئ أباً صحيحاً فعلاً أو ارفض الطلب أو رحل مخططاً بمراجعة. اجمع تغييرات العمل اللازمة في معاملة عند الحاجة. لا تفترض أن التقاط الفشل ألغى كل السابق؛ افحص الحالة ونظف عند المالك. ويجب حل المخالفة المؤجلة قبل حد التثبيت المطلوب لا اعتبار التأجيل إعفاءً من القاعدة.
تحقق من نجاح الإصلاح
اختبر الانتقال الفاشل ونظائره الصحيحة: الأب الغائب والاختياري والمطلوب والحذف والتثبيت المؤجل. نفذ foreign_key_check على النسخة المقصودة وصالح العمل؛ ولا تمنح integrity_check وحدها كل ضمان العلاقة والمجال.
امنع تكرار المشكلة
- اضبط السياسة وافحصها عند التهيئة، ووثق مفاتيح الأب والابن وافهرس وصول الابن عند مبرر، واختبر الكتّاب والترحيل. احفظ هوية المصدر وسياق الرفض دون كشف صفوف شخصية.