30 June 2009

Dude, where's my data access?

בהעמקת הכרותנו עם שכבת הממשק משתמש, אפשר כבר לראות את הצל של שכבת הלוגיקה המתקרבת. הגיע הזמן לקצת תכנון.

הנושא של היום הוא השאלה איפה לשים את הקוד שמפיק את שאילתותנו מול מסד הנתונים. החלטנו בשלב מוקדם יותר (ראה להלן) להשתמש ב
Linq to SQL
לשכבת ה
DAL.

LINQ to SQL,
כשגוררים עליו טבלאות ממסד נתונים של
SQL Server,
אוטומטית קורא ומפיק את היחסים בין הטבלאות שהגדרת במסד הנתונים






כששומרים את הקובץ
Linq to SQL,
מופק אוטומטית
מחלקה בשם
DataContext - הקשר-נתונים

ביחד עם כל המחלקות שצריך כדי להציג את הישויות שלך כאובייקטים, כולל יכולות שמירה וקריאה למסד הנתונים.


המחלקות שאנחנו תכלי'ס כתבנו בשכבת ה
DAL
מבצעות את הלוגיקה הכי בסיסית של
CRUD (create, retrieve, update, and delete)

על כל סוג של ישות בנפרד. אציין שככה לא צריך אף פעם לגזור מחרוזת
SQL.
ואם בנינו נכון את היחסים, אף פעם לא צריך לבנות שאילתת
Linq
שמשמתמש ב
join.
המחלקות שיצר לנו את מחלקת ההקשר-נתונים אמורים לעשות לנו את כל העבודה.

היופי בזה הוא בכך שאם יש לי ביד ישות "בנאדם" או אוסף שלהן, כל עוד שהוא מקושר למחלקת ההקשר-נתונים (ז"א, לא עבר תהליך סריליזציה - נושא לכניסה אחרת) אפשר "למשוך" על מספרי הטלפון של הבנאדם (עם זו פעם הראשונה למופע הזה, לפחות) ואז הוא יבצע שאילתא מול מסד הנתונים ויוציא את המידע הצריך.

והינה השאלה של היום: כמה מהמשיכה הזו נכון לעשות בשכבת הלוגיקה?

פרט זה, של מתי מתבצע השאילתא, זה לא ענין, אלא איזה קוד אחראי על ביצועו. לכן אם קוד מופק אוטומטית של הקשר-נתונים נמצא בשכבת ה
DAL
וקיימת שורה בשכבת הלוגיקה שגורמת לו להתבצע, האם שברנו אף חוק של תכנות ב3 שכבות? נדמה לי שלא. ואם נחליט בתאריך מאוחר יותר להשתמש בטכנולוגיה אחרת בשכבת ה
DAL,
נוכל לספק מחלקות שמחשפות אובייקטים מיוחסים כמו אלה של
Linq to SQL.
ושכבת הלוגיקה לא צריכה אף פעם לדאוג מתי נקרא המידע ממסד הנתונים.

-------------------------------------------------

As we dig deeper into the UI layer, the ghostlike form of the Business Logic layer (BL) is peering out at us from the future. A little planning is in order.

Today's issue is the question of where to place the code that generates our queries on the DB. We decided at an early stage (see below) to use LINQ to SQL for our Data Access layer (DAL).

LINQ to SQL, when you drag tables from an SQL Server database onto it, automatically reads and generates the existing relationships between your tables.








When you then save your LINQ to SQL class, called a DataContext, it autogenerates a code file with all the classes necessary to

1) represent your data entities in your program as business entities

2) persist your entities to the database




The classes we wrote for the DAL do the very barest CRUD logic (create, retrieve, update, and delete) on one entity type at a time. Note that with LINQ to SQL, we need not ever write a single SQL string. If we built the relationships correctly, furthermore, we need not ever write a single LINQ query with a "join" - because the DataContext should be doing that all for us.

The beauty of LINQ is that once I have a Person or collection of Persons, as long as it is still attached to the generating DataContext (that means it has never been serialized and deserialized... a topic for a different post), I can pull on Person.Phones and that will (the first time I call it for this instance) query the database for the phone objects related to the person at hand.

And so, the question: how much of this pulling can responsibly be done in the BL?

The detail of when the query is executed is not an issue, it's only a question of which code is reponsible for doing it. So if the autogenerated code for the DataContext is in the DAL, and a line in the BL causes it to fire and query the DB, have we violated any priciple of 3-layered structure? I don't think we have. And if we decide at some later date to use LINQ to Entities or some other mechanism in our DAL, we can provide classes that expose the related objects just as well as LINQ to SQL does. And the BL need never worry about when the data is read from the DB.

No comments:

Post a Comment