المحطّة ٢: تصميم البيانات — المخطّط العلائقي والفئات
حوّل المتطلّبات إلى جدولين وعلاقةٍ ومخطّطٍ جاهزٍ للتنفيذ. ⏱ نحو 22 دقيقة.
- تستخرج الكيانات والخصائص من المتطلّبات.
- تصمّم علاقة واحد ← متعدّد بمفتاحٍ أجنبيّ.
- تترجم المخطّط إلى أوامر
CREATE TABLEبأنواعٍ وقيودٍ سليمة. - توثّق تصميمك في قاموس بيانات.
١من المتطلّبات إلى الكيانات
كل اسمٍ مهمٍّ في متطلّباتك مرشّحٌ ليكون كيانًا (جدولًا). اقرأ قصص المحطّة السابقة واستخرج الأسماء: مستخدم، مهمّة. هذان كياننا، وكلٌّ يصير جدولًا.
ثم اسأل عن خصائص كل كيان (أعمدته): ما الذي نحفظه عن المستخدم؟ اسمه وكلمة مروره. وعن المهمّة؟ عنوانها وحالتها وصاحبها.
هذا التصميم يأتي قبل كتابة أيّ SQL. المخطّط الخاطئ يكلّفك إعادة بناءٍ مؤلمةً لاحقًا؛ أمّا المخطّط الجيّد فيجعل كل استعلامٍ لاحقٍ سهلًا.
٢العلاقة: المستخدم الواحد يملك عدّة مهامّ
هذا جوهر التصميم: العلاقة واحد ← متعدّد (One-to-Many). المستخدم الواحد له عدّة مهامّ، والمهمّة الواحدة لمستخدمٍ واحد. نمثّلها بوضع مفتاحٍ أجنبيّ user_id في جدول المهامّ يشير إلى users.id:
٣المخطّط بصيغة SQL
نترجم المخطّط إلى أوامر إنشاءٍ فعليّة. لاحظ كيف يعمل الكود نفسه على SQLite (المختبر) و MySQL (XAMPP) بفروقٍ طفيفةٍ في الأنواع:
-- SQLite (المختبر) / MySQL (XAMPP): الفروق في التعليقاتCREATE TABLE users ( id INTEGER PRIMARY KEY, -- MySQL: INT AUTO_INCREMENT PRIMARY KEY username TEXT NOT NULL UNIQUE, -- MySQL: VARCHAR(50) ... UNIQUE pass_hash TEXT NOT NULL, -- MySQL: VARCHAR(255) (bcrypt ~60 حرفًا) created_at TEXT -- MySQL: DATETIME);CREATE TABLE tasks ( id INTEGER PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(id), -- المفتاح الأجنبيّ: يربط المهمّة بصاحبها title TEXT NOT NULL, done INTEGER NOT NULL DEFAULT 0, -- 0 = غير منجَزة، 1 = منجَزة created_at TEXT);
نقاط التصميم المهمّة:
idمفتاحٌ رئيسٌ يتولّد تلقائيًّا لكل صفّ.usernameعليهUNIQUEفلا يتكرّر اسم مستخدم.pass_hashيتّسع لتعميةbcrypt(نحو 60 حرفًا) — لا نحفظ كلمة المرور الصريحة أبدًا (محطّة 4).user_idمفتاحٌ أجنبيٌّ يربط كل مهمّةٍ بصاحبها — وهو أساس «كلٌّ يرى مهامّه فقط».doneعددٌ(0/1)يمثّل حالة الإنجاز.
٤قاموس البيانات: توثيقٌ موجز
أكمل تصميمك بجدولٍ صغيرٍ يشرح كل عمودٍ ونوعه وقيده — يسمّى قاموس البيانات، ويفيد كل من يقرأ مشروعك (أو أنت بعد شهر):
| الجدول | العمود | النوع | القيد/المعنى |
|---|---|---|---|
| users | username | VARCHAR(50) | فريد، لا يفرغ |
| users | pass_hash | VARCHAR(255) | تعمية bcrypt، لا يفرغ |
| tasks | user_id | INT | مفتاح أجنبيّ ← users.id |
| tasks | done | TINYINT | 0 أو 1، افتراضيًّا 0 |
توقّع وتحقّق
العلاقة بين المستخدم والمهمّة في مشروعنا هي:
أين نضع المفتاح الأجنبيّ user_id؟
لماذا نفصل users عن tasks بدل جدولٍ واحد؟
ما النوع المناسب لعمود pass_hash في MySQL؟
bcrypt نحو 60 حرفًا؛ نترك سعةً للمستقبل.الخلاصة
- الأسماء المهمّة في المتطلّبات تصير كياناتٍ (جداول).
- علاقة واحد ← متعدّد تُمثَّل بمفتاحٍ أجنبيّ في طرف «المتعدّد» (
user_idفيtasks). - فصل الكيانات (التطبيع) يمنع التكرار والتناقض.
usernameفريد، وpass_hashواسعٌ لتعميةbcrypt، وdoneعددٌ0/1.- قاموس البيانات يوثّق كل عمودٍ ونوعه وقيده.
تحدٍّ تصميمي: مخطّط بيانات «مفكّرة مهامّي»
تصميميصمّم قاعدة بيانات مشروعك: ارسم المخطّط العلائقي (ERD)، واكتب أوامر الإنشاء، ووثّق الأعمدة في قاموس بيانات. سنُنفّذ هذا التصميم فعليًّا في المحطّة القادمة.
- مخطّط ERD يبيّن الجدولين والعلاقة واحد ← متعدّد.
- أوامر CREATE TABLE للجدولين مع الأنواع والقيود.
- قاموس بياناتٍ موجزٌ لكل عمود.