משך: 4 שעות אקדמיות (180 דקות).

מטרת השיעור: הסטודנטים יריצו שרשרת שלמה מאפס — Docker ל-DB, DbContext, Migrations, ושני endpoints אמיתיים — ולא רק יבינו את הרעיון בתיאוריה.

בסוף השיעור הסטודנטים צריכים: להרים SQL Server בעצמם ב-Docker, להגדיר DbContext עם DbSet, ליצור ולהחיל Migration, ולהריץ API שבאמת קורא/כותב ל-DB דרך שני endpoints (GET/POST).

דגש קריטי: זהו השיעור הכי “ידיים על המקלדת” עד כה ביחידה — כל שלב תלוי בשלב שלפניו (בלי Docker רץ, שום דבר אחר לא יעבוד), ורצוי לעבור אותם ממש לפי הסדר, לא ברצף שקופיות בלבד. קשרו במפורש לסכמה שתוכננה בשיעור הקודם — זו לא סכמה חדשה, זו אותה סכמה, רק ממופה מקוד C#.


מהלך השיעור

חלק בשיעורמשךהערות ודגשים
פתיחה וחיבור5 דקותהזכירו CREATE TABLE ידני מהשיעור הקודם — “יש דרך פשוטה יותר?”
NuGet Packages + dotnet-ef10 דקותdotnet add package — ספרייה חיצונית, לא מובנית; dotnet tool install --global = כלי טרמינל, לא קוד
מרימים Docker ל-DB20 דקותdocker run עם -e/--name/-d (חדשים מול היחידה הקודמת), docker ps/docker logs לאימות
Entities: Student/Grade15 דקותהדגישו למה class ולא record כאן — EF Core צריך Properties ניתנים לשינוי
DbContext15 דקותקונסטרוקטור עם DbContextOptions — קשרו ל-Constructor Injection מ-DI
Program.cs + AddDbContext20 דקותמחרוזת חיבור מקטע-מקטע (Server, Database, User Id/Password, TrustServerCertificate)
הדגמה חיה: Migrations25 דקותmigrations add (מתכנן) מול database update (מבצע בפועל) — הראו את שני השלבים בנפרד
Controller + 2 endpoints25 דקותGET/POST ישירות מול DbContext; SaveChanges()
מריצים ובודקים20 דקותcurl על שני ה-endpoints; הוכיחו persistence — restart ל-dotnet run, הנתונים עדיין שם
Navigation Properties10 דקותתקציר בלבד — List<Grade> בתוך Student; העומק בשיעור העתידי על Queries
תרגול מודרך15 דקותתרגיל 1+2

דגשים להעברת השיעור

  • זה שיעור שדורש סביבת עבודה תקינה לכולם לפני שמתחילים — ודאו ש-Docker Desktop רץ אצל כל סטודנט לפני חלק ה-DB, אחרת מבזבזים זמן שיעור על פתרון תקלות התקנה במקום על התוכן.
  • ההדגמה החיה של migrations add+database update היא הליבה של השיעור — סטודנטים צריכים לראות בעיניים את קובץ ה-Migration שנוצר ואת הטבלה שמופיעה ב-DB בפועל, לא רק להאמין שזה קורה.
  • הדגישו בתקיפות ש-SaveChanges() הוא לא “עוד קריאה” — זה הרגע היחיד שנתונים נכתבים בפועל. שכחת SaveChanges היא הבאג הכי נפוץ בשלב הזה.
  • שלב ה"מריצים ובודקים" הוא לא קישוט — ההוכחה שדנה “שורדת” restart של dotnet run היא מה שממחיש בפועל את ההבדל בין DB אמיתי ל-List<T> בזיכרון מכל השיעורים הקודמים. אל תדלגו עליו.
  • אם יש זמן, השוו קצרות ל-InMemoryRepository מיחידה קודמת — “DbSet<T>.Add נראה בדיוק כמו List<T>.Add, אבל התנהגות שונה לגמרי מתחת למכסה”. הזכירו שה-Controller בשיעור הזה מדבר עם DbContext ישירות בכוונה (לצורך הוכחה מהירה), ושבשיעור הבא זה יתחבר כמו שצריך דרך ה-Repository.

מושגים

NuGet Package — ספרייה חיצונית שמתווספת לפרויקט (dotnet add package), לא מובנית ב-.NET. ORM — שכבת מיפוי בין אובייקטים לטבלאות SQL. DbContext — חיבור לוגי למסד הנתונים, מקבל הגדרות חיבור דרך הקונסטרוקטור. DbSet<T> — טבלה בודדת בתוך ה-DbContext. Connection String — כתובת+פורט+שם DB+פרטי התחברות, כמחרוזת טקסט אחת. Code First — מחלקות C# קודם, DB נבנה מהן. Migration — קובץ שמתעד שינוי מבני ב-DB (migrations add מתכנן, database update מבצע).


תרגיל חשיבה

שאלת פתיחה: “הוספתם שדה חדש למחלקת Student (למשל PhoneNumber), אבל לא הרצתם migrations add. מה קורה כשמנסים לשמור תלמיד חדש עם מספר טלפון?”

מהלך: תנו לסטודנטים לשער — התשובה: שגיאת ריצה, כי העמודה PhoneNumber פשוט לא קיימת בטבלה ב-DB בפועל. הובילו לתובנה: המחלקה ב-C# והטבלה ב-DB חייבות תמיד להישאר מסונכרנות — Migration היא הגשר שמבצע את הסנכרון הזה, לא פעולה אופציונלית.

מה המרצה מראה בסוף: הוסיפו שדה חדש למחלקה בשידור חי, נסו לשמור בלי Migration (הראו את השגיאה), ואז הריצו migrations add+database update ותנו לאותה שמירה להצליח — הדגמה ישירה של הצורך בסנכרון.