אפליקציית דמו אחד ועוד אחד פיתוח תוכנה לוגו
מצגת 01

שכבת הנתונים
DataAccessLayer

איך ישות אחת הופכת לטבלה ב-DB, בלי SQL ידני ובלי מיגרציות.

מה תפקיד השכבה?

  • כל הגישה לבסיס הנתונים עוברת כאן — אף שכבה אחרת לא כותבת SQL.
  • ‏ORM קטן וממוקד משלנו: Record + אטריביוטים, בלי Entity Framework.
  • תומכת בשלושה ספקים באותו קוד בדיוק: SQL Server, MySQL, SQLite.
  • אסינכרונית מקצה לקצה — כל פנייה ל-DB היא await, אף Thread לא נחסם.
Record IDataSupplier SqlDataAccess MySqlDataAccess SqliteDataAccess

‏Record — הלב של השכבה

  • לכל ישות יש ID (מפתח ראשי) ו-Description.
  • מסמנים תכונה ב-[Column] — והיא עמודה ב-DB.
  • שם הטבלה = שם המחלקה; המפתח = שם+Id.
  • אין ALTER ידני: SetupAsync בעליית האפליקציה יוצרת טבלאות חסרות ומוסיפה/מרחיבה עמודות לפי הקוד.
public class Car : Record
{
    [Column(Size = 300)]
    public override string Description { get; set; }

    [Column] public bool IsAutomatic { get; set; }
    [Column] public double Volume { get; set; }
    [Column] public string Color { get; set; }
    [Column] public DateTime ProductionDate { get; set; }
}

זהו כל הקוד שנדרש כדי שטבלת Car תקום ב-DB ותנוהל במסך.

CRUD אסינכרוני

Car c = new Car { Description = "מאזדה 3", Volume = 2.0 };
await c.SaveAsync();                    // INSERT (‏ID חדש) או UPDATE — אוטומטית

Car loaded = await Record.GetAsync<Car>(c.ID);      // טעינה לפי מפתח
List<Car> all = await Record.AllAsync<Car>();       // כל הרשומות
int n        = await Record.CountAsync<Car>();      // ספירה

c.Color = "אדום";
await c.UpdatePropertiesAsync("Color");  // עדכון עמודה בודדת — לא Save מלא!

await c.DeleteAsync();
  • כלל בית: עדכון נקודתי = UpdatePropertiesAsync, לא SaveAsync — כדי לא לגרור תופעות לוואי של שמירה מלאה.
  • DateTime.MinValue פירושו "אין תאריך" — נשמר כ-NULL.

שאילתות מסוננות — AndFilter

AndFilter f = new AndFilter();
f.Add("color", "אדום");                          // שוויון, עם פרמטר
f.Add("volume", 1.6, EqalityOperators.GreaterThan);
f.AddBetween("productionDate", from, to);

List<Car> cars = await Record.PartialAsync<Car>(f, "productionDate desc",
                                                pageNumber: 0, pageSize: 20);
int total     = await Record.CountAsync<Car>(f);
  • הפילטר בונה WHERE עם פרמטרים — בלי שרשור מחרוזות ובלי SQL Injection.
  • OrFilter משלים תנאי "או"; עימוד דרך PagingTemplate של כל ספק.

איך אותו קוד רץ על שלושה בסיסי נתונים?

  • הספק נבחר לפי מחרוזת החיבור: ‏Server= ← ‏MySQL, ‏Data Source=*.db ← ‏SQLite, אחרת ← ‏SQL Server.
  • הקוד כותב T-SQL; ‏FixSql של כל ספק מתרגם: ‏GETDATE(), ‏ISNULL, ‏[סוגריים], ‏IDENTITY
  • ‏SQLite מקבל גם פונקציות YEAR/MONTH/DAY שהוגדרו ב-C#.
  • פיתוח מקומי על SQLite, ייצור על SQL Server/MySQL — בלי לשנות שורה.

עוד כלים בארגז

  • הצפנה:[Column(IsEncrypted = true)] — הערך מוצפן AES לפני הכתיבה ומפוענח בקריאה.
  • סריאליזציה:SerializeType = Json שומר אובייקט שלם בעמודת טקסט.
  • אינדקסים:CreateIndexAsync("color") — נוצר רק אם אינו קיים, בכל ספק.
  • ייבוא:ImportAsync מזהה רשומות קיימות לפי IsUniqueId ומעדכן במקום לשכפל.
  • טרנזקציות:BeginTransactionAsync / CommitTransactionAsync.

לסיכום: מגדירים ישות, מסמנים עמודות — והשכבה עושה את כל השאר.