התערבות ב- AutoGenereted Code של EF
-
בהבאת טבלה חדשה לEF נוצר ישות באופן אוטומטי הכולל Class וקונסטרקטור וכו'.
הבעיה היא שברגע שנוצר קונסטרקטור, אני יותר לא יכול לדרוס אותו, ואני לא יכול לעשות בו שימוש, לדוגמא, אני רוצה לקבוע ערך כלשהיא לשדה מסויים בעת שהוא נוצר.
הפיתרון היא להתערב בקוד האוטומטי שנוצר, ולהוסיף לישות מתודה בשם OnCreated למשל, ולקרוא לו מהקונסטרקטור, ואז אוכל לדרוס אותו מכל מקום ולהוסיף לא פעולות שיתבצעו בהיווצרות האוביקט.
השאלה איך עושים זאת ? איך מתערבים בקוד האוטומטי כך שהוא יצור גם את המתודה האמורה ?
תודה מראש על הפתרונות.פורסם במקור בפורום CODE613 ב23/03/2015 20:01 (+02:00)
-
כמו שבטח הבנת אי אפשר לכתוב ידנית בקוד האוטומטי כי זה יידרס בפעם הבאה שהקוד יתעדכן,
אני לא מכיר EF אבל בחשיבה פשוטה של OOP תירש את הקלאס הזה לקלאס שלך ושם תעשה בקונסטרקטור מה בא לך . . . (אא"כ הוא sealed)אם אנחנו מדברים ספציפית על EF, ר' גוגל מצא לי משהו מעניין: יש את הענין של Partial Class, למי שלא מכיר בקצרה זה אומר שאתה יכול ליצור עוד קובץ לקלאס מסוים ולהוסיף בו עוד מתודות שיהיו חלק מהקלאס
ועל אותו רעיון יש גם Partial Methods שמתודה שנמצאת בקלאס האוטומטי יכולה להמשיך בקלאס השני, במקרה שלך הבעיה היא שאין PARTIAL CONSTRUCTOR (עדיין)
אבל בכ"ז יש פתרון כי ה EF בסוף הקונסטרקטור שלו קורא ל Partial Method בשם OnCreated אז פשוט תייצר partial class לקלאס האוטומטי ושם תשים Partial Method בשם OnCreated ושים שם את הלוגיקהמקור:
פורסם במקור בפורום CODE613 ב24/03/2015 03:14 (+02:00)
-
ראשית, תודה על התייחסותך. אכן, הבנת טוב את הבעיה. אך אני מעוניין בפתרון מסוג אחר וכדלהלן:
יש קובץ DataModel.tt שם ההגדרות לקוד שייוצר אוטומטי, ושם ניתן לשנות הגדרות שונות למשל הגדרת אוסף כלשהיא שיהיה מסוג ObservableCollection במקום ICollection וכד'. כך כמדמני, אפשר להגדיר מתודות שיווצרו בופן אוטומטי. כשזה מוגדר שם, כל פעם שיווצר הקוד מחדש זה יווצר לפי ההגדרות שם. וזאת אני רוצה לדעת איך להוסיף את המתודה המתבקשת בקובץ ההוא. זה יחסוך את העבודה של הורשות וכו'.
תודה.
ראה דוגמה:פורסם במקור בפורום CODE613 ב24/03/2015 11:55 (+02:00)
-
אני מבין שמדובר בModel First או Db First.
זאת אומרת הפרויקט שלך מכיל קובץ בשם edmx, ועל פיו נוצרים בזמן קמפול כל המחלקות. והשאלה באמצעות איזה כלי זה נעשה. בכלים הישנים זה היה יוצר מחלקות היורשות כולם מEntityObject ובכלים החדשים זה יוצר POCO - מחלקות רגילות לגמרי שלא יורשים מכלום.
בדוק את חתימת המחלקה שנוצרת אוטומטי, היא מכילה ירושה מEntityObject?
בכל אופן יש לך מגוון דרכים.-
partial class
כמו שsoft אמר, תוכל ליצור בפרויקט מחלקה ששמה כשם הישות, עם הציון partial, ואז אתה בעצם כאילו כותב קוד במחלקה המקורית רק שקוד זה לא יידרס. soft כתב שעדיין לא תוכל להרחיב את הConstructor, מכיון שזה לא נתמך בינתיים. אציין רק שלעיתים אין בכלל קונסטרקטור בקוד האוטומטי (הסיבה שיש בפעמים אחרות זה בשביל הDefaultValue ואיתחול הCollectionים) וא בהחלט אפשר לכתוב Constructor במחלקה אותה ציינת כpartial.
בקשר לOnCreate: אני לא יודע לאיזה מתודה התכוון soft, אם היא אכן קיימת זה מצויין לדרוס אותה בירושה או בpartial. -
DefaultValue:
אם לא מדובר בלוגיקה אלא סתם ערך סטטי פשוט, אז יש בסכמת הedmx אפשרות ששמה Default Value. היא איננה מקבלת ערך בחלון העיצוב, אבל אם תיכנס לXML ע"י קליק ימני וOpen With > XML Edtor תוכל לאתר את המאפיין בקובץ ולהוסיף לו "DefaultValue" הנה לדוגמה מאפיין Name שמעתה יכיל בעת יצירתו ערך 123:<Property Name="Name" DefaultValue="123" Type="String" Nullable="false" />
בקוד שנוצר אוטומטי ישנה הצבה של הערך בתוך מתודת הConstructor. -
ירושה - של הישות:
שים לב שהמופעים של הישויות נוצרים בשתי דרכים: או אוטומטי ע"י הEF בעת טעינה מהDB, או ע"י קוד שלך לשם רשומות חדשות. אם הערך האוטומטי הוא בשביל רשומות חדשות, די אם תירש מהמחלקה כמו שהציע soft. זה ממש פשוט, אתה יוצר מחלקה כזו בכל מקום בפרוייקט שלך. נניח לישות שלך קוראים User, אז הנה במחלקה היורשת:public class UserCustomize : User
{
public UserCustomize()
{
//yoyr code.
}
}
ואז במקום כזה קוד:var user = new User();
db.UserSet.Add(user);
אתה משתמש בתת המחלקה שיצרת, UserCustomize:var user = new UserCustomize();
db.UserSet.Add(user); -
לכדית זמן השמירה למסד בDbContext
תוכל לרשת/להרחיב ע"י partial את מחלקת הקונקסט. ואז לדרוס את מתודת SaveChange. שם תוכל לעבור על כל האובייקטים שהולכים להיכנס למסד, לבדוק איזה ישות הם ולפי זה להציב במאפייניהם ערכים. דוגמה:public partial class ModelContainer
{
public override int SaveChanges()
{
var changedEntities = ChangeTracker.Entries();foreach (var changedEntity in changedEntities) { if (changedEntity.State == EntityState.Added) { if (changedEntity.Entity is User) //בודק שמדובר בישות המתאימה { var user = (User)changedEntity.Entity; user.DateCreate = DateTime.Now; //הערך להצבה } /* else if (changedEntity.Entity is ... // פה טיפול בישויות מסוג אחר אם צריך else if (changedEntity.Entity is ... */ } } return base.SaveChanges(); }
}
פורסם במקור בפורום CODE613 ב24/03/2015 13:33 (+02:00)
-
-
ראשית, תודה על התייחסותך. אכן, הבנת טוב את הבעיה. אך אני מעוניין בפתרון מסוג אחר וכדלהלן:
יש קובץ DataModel.tt שם ההגדרות לקוד שייוצר אוטומטי, ושם ניתן לשנות הגדרות שונות למשל הגדרת אוסף כלשהיא שיהיה מסוג ObservableCollection במקום ICollection וכד'. כך כמדמני, אפשר להגדיר מתודות שיווצרו בופן אוטומטי. כשזה מוגדר שם, כל פעם שיווצר הקוד מחדש זה יווצר לפי ההגדרות שם. וזאת אני רוצה לדעת איך להוסיף את המתודה המתבקשת בקובץ ההוא. זה יחסוך את העבודה של הורשות וכו'.
תודה.
ראה דוגמה:זה נכון, אם אתה משנה בT-Template אתה יכול להוסיף "קוד קשיח" - איננו אוטומטי ותלוי במקור המודל, אבל זה לא מומלץ כלל. ייתכן שבעתיד תשנה את הTT.
אבל זה רעיון נהדר להוסיף מתודה לעת יצירה בTT. הנה אחד שמדגים זאת, שאפו tchaym על הרעיון. אני ממש מתלהב מהקלות.עריכה:
זה קצת שונה מהפשטות בלינק דלעיל, הקוד המקורי נראה משהו כזה:if (propertiesWithDefaultValues.Any() || collectionNavigationProperties.Any() || complexProperties.Any()) { #> public <#=code.Escape(entity)#>() ...
מה שקורה כאן, זה שנוצר קונסטרקטור רק אם יש אוסף או ערך ברירת מחדל. ואילו אנו רוצים שתמיד יהיה קונסטרקטור שיפעיל מתודה בשם OnInit. אז הכי שפו להוריד את התנאי בכלל, או להציב true בתנאי כך שתמיד יתקיים - ככה זה אמור להיראות כל השינוי:
if (true) { #> partial void OnInit(); public <#=code.Escape(entity)#>() { OnInit();
פורסם במקור בפורום CODE613 ב24/03/2015 13:40 (+02:00)
-
תודה דוד ל.ט. על רוחב הלב שלך בפירוט אפשרויות שונות. אכן פתרונות יצירתיות. אך לצערי עם רובן יש לי בעיה, ואפרט לפי סדר הפיתרונות שהבאת:
- אכן כפי שכתבת, לא ניתן לדרוס קונסטרקטור שנוצר אוטומטי, וזה בדיוק מה שאני צריך.
- DefaultValue לא מספיק לי כי אני צריך להכניס קצת לוגיקה - וכפי שכתבת. בנוסף: במקרה שאני אמחק את הישות ואייבא אותו מחדש, הכל יתאפס, וזה כמו שאסיף לוגיקה לקוד שנוצר אוטומטי, שיימחק רק במקרה שאמחק את הישות, ואז כאשר אייבא אותו מחדש הכל יתאפס.
- ירושה זה אכן יכול להיות פיתרון, אבל זה לא נעים לשכתב מחדש ישויות ולהסתבך עם שמות...
- אני נדרש להציג עוד לפני השמירה את הנתונים, ולהגדיר את הנתונים בזמן השמירה זה כבר די מאוחר.
5. זה אכן הפיתרון המוצלח, אך הבעיה היא שאני פשוט לא הבנתי איך לכתוב ולהשתיל זאת בT-Template. אשמח מאוד עם תעזור לי בזה.
ושוב תודה על רוחב הלב שלך.
פורסם במקור בפורום CODE613 ב27/03/2015 00:33 (+02:00)
-
שים לב, שהבעיה שכתבת בסעיף 3, היא לא ממש הגיונית. מדובר על שינוי אחד (וגם זה לא בהכרח) כל פעם שאתה מייבא.
וגם לפי הפתרון הנכסף, אתה בבעיה זו כמו שתראה בפירוט דלקמן (צעד 6). אז אסביר איך לשנות את הTT. הרי הTT זה הוראות איך ליצור את המחלקות. יש לופ שעובר על השויות ולפי זה מכניס בונה מחלקות וכו'.
הנה הצעדים לעריכה עליה התכוונתי:-
אתה פותח את הקובץ בעל הסיומת tt
-
מחפש את השורה הזו:
if (propertiesWithDefaultValues.Any() || collectionNavigationProperties.Any() || complexProperties.Any())
-
מחליף אותה בזו:
if (true)
-
שתי שורות אחרי כן, אחרי השורה עם הסימן "#<", אתה מוסיף שורה זו:
partial void OnInit();
זו הצהרה על מתודה חלקית (ניתנת להרחבה בקובץ אחר בפרוייקט). -
שתי שורות אחרי כן, אחרי תחילת המתודה הזו public <#=code.Escape(entity)#>(), אתה מוסיף שורה זו:
OnInit();
זו קריאה למתודה שיצרנו. -
בקובץ כלשהו בפרוייקט אתה חייב ליישם את גוף המתודה OnInit, משהו כזה:
public partial class EntityNameHer...
{
partial void OnInit()
{
...
}
}
נ.ב. אתה יכול להשתמש עם אירוע במקום עם מתודה, ובלי partial.
בשביל זה יש לשנות בצעדים דעיל' ובמקום שיראה ככה:if (true) { #> partial void OnInit(); public <#=code.Escape(entity)#>() { OnInit();
צריך להיות ככה:
if (true) { #> public event Action<<#=code.Escape(entity)#>> OnInit; public <#=code.Escape(entity)#>() { if (OnInit!=null) OnInit(this);
ובקוד שלך בזמן כל שהוא בטעינת התוכנה אתה מוסיף אירוע ככה:
Item.OnInit += Item_OnInit;
הItem זה שם הישות.
בטיפול באירוע אתה מאתחל מה שאתה רוצה.בהצלחה רבה, תגיד מה עשית בסוף ולמה.
בנוסף, ברוך הבא לפורום ומקוה שהמקום ימצא חן בעיניך.פורסם במקור בפורום CODE613 ב29/03/2015 09:59 (+03:00)
-
-
תודה על סבלנותך, דוד ל.ט. זה עובד מצויין.
בחרתי בשינוי קובץ ה Template, זה הכי נח לי, אבל קיבלתי את כל ההצעות להזדמנויות אחרות...
רק רציתי להבין מה כוונתך שאולי בעתיד אשנה את קובץ הTemplate? אם אשנה אז אתייחס גם לזה, לא ?פורסם במקור בפורום CODE613 ב30/03/2015 02:06 (+03:00)