طَبِّقْهاتعلّم المبدأ، وطبّقه بيدكمقرر 241 · تحليل وتصميم برمجيات الويب
الدرس 9 · الوحدة 4: تحويل المواصفات الوظيفية إلى مواصفات تقنية

العلاقات ومخطط الكيانات ERD

كيف ترسم العلاقات بين الأصناف، ثم تحوّلها إلى تصميم قاعدة بيانات بمفاتيح وجداول ربط؟ ⏱ نحو 45 دقيقة.

بعد هذا الدرس ستستطيع أن:
  • ترسم علاقات الارتباط والوراثة والتركيب والتجميع مع التعدد.
  • تميّز التركيب من التجميع والوراثة من الارتباط.
  • تحوّل نموذج الأصناف إلى مخطط كيانات بمفاتيح أساسية وأجنبية.
  • تحل علاقة كثير إلى كثير بجدول ربط.

١الأصناف لا تعيش وحدها

في الدرس السابق رسمنا الأصناف منفصلة. لكن المتطلبات مليئة بالعلاقات: «المدرب يقدّم دورات»، «الدورة تتكون من محاضرات»، «المتدرب نوع من المستخدمين». هذه العلاقات هي ما يحدد لاحقًا المفاتيح الأجنبية في قاعدة البيانات والروابط في الكود.

العلاقةالرمز في Mermaidتعنيمثال
ارتباطA "1" --> "0..*" BA يعرف B، مع التعدد على الطرفينمدرب واحد يقدّم صفرًا أو أكثر من الدورات
وراثةUser <|-- TraineeTrainee نوع من User ويرث خصائصهالمتدرب والمدرب كلاهما مستخدم
تركيبCourse *-- Sessionجزء لا يعيش دون الكل؛ يُحذف بحذفهالمحاضرات تُحذف إن حُذفت الدورة
تجميعCourse o-- Trainerجزء مستقل يعيش وحدهالمدرب يبقى إن حُذفت الدورة

٢العلاقات في مخطط الأصناف

diagram.mmd
classDiagram  class User["المستخدم"] {    +int id    +String name    +String email  }  class Trainee["المتدرب"]  class Trainer["المدرب"] {    +String specialty  }  class Course["الدورة"]  class Session["المحاضرة"]  class Enrollment["التسجيل"]  User <|-- Trainee  User <|-- Trainer  Course *-- "1..*" Session : تتكون من  Trainer "1" --> "0..*" Course : يقدّم  Trainee "1" --> "0..*" Enrollment : له  Course "1" --> "0..*" Enrollment : فيها

تتكون من

يقدّم

له

فيها

1..*

1

1

1

0..*

0..*

0..*

المستخدم

+int id

+String name

+String email

المتدرب

المدرب

+String specialty

الدورة

المحاضرة

التسجيل

اقرأ الأسهم: المثلث المفرغ <|-- وراثة، والمعيّن الممتلئ *-- تركيب، والأرقام على طرفي الارتباط التعدد. جرّب: أضف صنف Payment وارتباطًا «التسجيل له دفعة واحدة أو لا شيء»: Enrollment "1" --> "0..1" Payment.

التعدديُقرأمثال
1واحد بالضبطلكل تسجيل متدرب واحد
0..1صفر أو واحدللتسجيل دفعة أو لا شيء (لم يدفع بعد)
0..* أو *صفر أو أكثرللمتدرب صفر أو أكثر من التسجيلات
1..*واحد أو أكثرللدورة محاضرة واحدة على الأقل

٣من الأصناف إلى قاعدة البيانات: مخطط الكيانات

المواصفات التقنية تحتاج أيضًا تصميم قاعدة البيانات. مخطط الكيانات والعلاقات ERD يحوّل الأصناف التي تُحفظ إلى جداول، والعلاقات إلى مفاتيح:

diagram.mmd
erDiagram  TRAINEE ||--o{ ENROLLMENT : "يسجّل"  COURSE ||--o{ ENROLLMENT : "تضم"  TRAINEE {    int id PK    string name    string phone UK  }  COURSE {    int id PK    string title    int capacity    decimal fee  }  ENROLLMENT {    int id PK    int trainee_id FK    int course_id FK    string status  }

يسجّل

تضم

TRAINEE

int

id

PK

string

name

string

phone

UK

ENROLLMENT

int

id

PK

int

trainee_id

FK

int

course_id

FK

string

status

COURSE

int

id

PK

string

title

int

capacity

decimal

fee

PK المفتاح الأساسي، وFK المفتاح الأجنبي الذي يشير إلى جدول آخر، وUK قيمة لا تتكرر. العلاقة بين المتدرب والدورة كثير إلى كثير (متدرب في دورات كثيرة، ودورة لمتدربين كثيرين)، فتُحلّ بجدول ربط ENROLLMENT يحمل مفتاحين أجنبيين، وبياناته الخاصة مثل status.

الرمزالمعنى
||واحد بالضبط
o|صفر أو واحد
o{صفر أو أكثر
|{واحد أو أكثر

يُقرأ TRAINEE ||--o{ ENROLLMENT: لكل تسجيل متدرب واحد بالضبط، ولكل متدرب صفر أو أكثر من التسجيلات. والمفتاح الأجنبي يوضع دائمًا في جدول طرف «الكثير».

٤قواعد التحويل

في نموذج الأصناففي قاعدة البيانات
صنف يُحفظجدول بمفتاح أساسي id
ارتباط واحد إلى كثيرمفتاح أجنبي في جدول طرف «الكثير»
ارتباط كثير إلى كثيرجدول ربط بمفتاحين أجنبيين (وقد يحمل بيانات إضافية)
واحد إلى واحد (اختياري)مفتاح أجنبي فريد UK في أحد الطرفين
عملية محسوبة مثل seatsLeft()لا عمود لها؛ تُحسب بالاستعلام
وراثةجدول واحد بعمود نوع type، أو جدول لكل صنف (قرار تصميمي يُوثَّق)

توقّع وتحقّق

«المحاضرات تُحذف إن حُذفت الدورة» علاقة:

أين يوضع المفتاح الأجنبي في علاقة واحد إلى كثير؟

ماذا يعني الرمز o{ في ERD؟

كيف تُحل علاقة كثير إلى كثير بين المتدرب والدورة؟

الخلاصة

تحدٍّ تصميمي: قاعدة بيانات «دورات»

متقدم

أكمل مخطط الكيانات لنظام «دورات»: المدرب يقدّم دورات كثيرة، والمتدرب يسجّل في دورات كثيرة عبر جدول ENROLLMENT، ولكل تسجيل دفعة واحدة أو لا شيء.

المطلوب:
  • خمسة جداول: TRAINEE و COURSE و TRAINER و ENROLLMENT و PAYMENT، ولكل منها مفتاح أساسي PK.
  • ENROLLMENT جدول ربط فيه trainee_id و course_id مفتاحين أجنبيين.
  • COURSE فيه trainer_id مفتاحًا أجنبيًّا، وعلاقة واحد إلى كثير مع TRAINER.
  • العلاقة بين ENROLLMENT و PAYMENT: واحد إلى صفر أو واحد.
✓ التحقق الآلي: يقرأ المختبر مخططك (العناصر والروابط) ويفحصه
  • المخطط مكتوب بصيغة صحيحة ويُرسم
  • نوعه: مخطط كيانات erDiagram
  • جدول TRAINEE
  • جدول COURSE
  • جدول TRAINER
  • جدول ENROLLMENT
  • جدول PAYMENT
  • COURSE له مفتاح أساسي
  • PAYMENT له مفتاح أساسي
  • ENROLLMENT فيه course_id FK
  • COURSE فيه trainer_id FK
  • متدرب واحد ← تسجيلات كثيرة
  • دورة واحدة ← تسجيلات كثيرة
  • مدرب واحد ← دورات كثيرة
  • تسجيل واحد ← دفعة واحدة أو لا شيء

💡 تلميح 1
انسخ سطر العلاقة وعدّله: COURSE ||--o{ ENROLLMENT : "تضم".
💡 تلميح 2
صفر أو واحد في طرف PAYMENT: ENROLLMENT ||--o| PAYMENT : "تُدفع بـ".
💡 تلميح 3
المفتاح الأجنبي في طرف «الكثير»: trainer_id يوضع في COURSE لا في TRAINER.

حاول بنفسك أولًا؛ للتصميم أكثر من حلّ صحيح، والفحص يتأكد من العناصر الأساسية فقط.

diagram.mmd
erDiagram  TRAINEE ||--o{ ENROLLMENT : "يسجّل"  COURSE ||--o{ ENROLLMENT : "تضم"  TRAINER ||--o{ COURSE : "يقدّم"  ENROLLMENT ||--o| PAYMENT : "تُدفع بـ"  TRAINEE {    int id PK    string name  }  COURSE {    int id PK    int trainer_id FK    string title  }  TRAINER {    int id PK    string name  }  ENROLLMENT {    int id PK    int trainee_id FK    int course_id FK    string status  }  PAYMENT {    int id PK    int enrollment_id FK    decimal amount  }

يسجّل

تضم

يقدّم

تُدفع بـ

TRAINEE

int

id

PK

string

name

ENROLLMENT

int

id

PK

int

trainee_id

FK

int

course_id

FK

string

status

COURSE

int

id

PK

int

trainer_id

FK

string

title

TRAINER

int

id

PK

string

name

PAYMENT

int

id

PK

int

enrollment_id

FK

decimal

amount

انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←

📝 معلم؟ أرسل ملاحظة للمؤلف عن هذا الدرس