דילוג לתוכן
  • דף הבית
  • קטגוריות
  • פוסטים אחרונים
  • משתמשים
  • חיפוש
  • חוקי הפורום
כיווץ
תחומים

תחומים - פורום חרדי מקצועי

💡 רוצה לזכור קריאת שמע בזמן? לחץ כאן!
  1. דף הבית
  2. תכנות
  3. ארכיון code613m
  4. שגיאה מוזרה באנטיטי

שגיאה מוזרה באנטיטי

מתוזמן נעוץ נעול הועבר ארכיון code613m
15 פוסטים 2 כותבים 1.1k צפיות
  • מהישן לחדש
  • מהחדש לישן
  • הכי הרבה הצבעות
התחברו כדי לפרסם תגובה
נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
  • A מנותק
    A מנותק
    avr416
    כתב ב נערך לאחרונה על ידי
    #1

    יש לי מחלקת רפוזיטורי שמטפלת בשמירה ועדכון האובייקטים בדטהבייס.

    יש לי קוד שעבד מצויין עד היום (כך לפחות זכור לי <!-- s:-) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":-)" title="מחייך" /><!-- s:-) -->), ומשום מה עכשיו אני מקבל את השגיאה הנ"ל:

    An entity object cannot be referenced by multiple instances of IEntityChangeTracker.

    שפירושה בעברית: שא"א לשייך את אותו אובייקט למספר מופעים של הDB.

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

    var donorVM = objUI as DonorVM;
    var donor = db.Donors.Include(d => d.Addresses)
    						 .Include(d => d.Communications)
    						 .Include(d => d.Categories)
    						 .Where(d => !d.Trash && d.Id == donorVM.Id)
    						 .FirstOrDefault();
    
    if (donor == null) return null;
    MapAllObjUIToDAL(donorVM, ref donor);
    //עד כאן: עדכנתי את האובייקט ששלפתי מהDB מהאובייקט שהגיע מהUI, ושמרתי אותו בDB
    db = new Model();
    //יצרתי מופע חדש של מחלקת המודל - כיון שאחרת הייתי מקבל שגיאה - ורק ככה זה עבד
    //הקוד הבא מעדכן את הסטייט של כל הinner joinים שהוא השתנה או נוסף, כדי שהאנטיטי ידע לעדכן גם אותם (כיון שהם שייכים לטבלאות אחרות
    db.Entry(donor.Addresses.First()).State = EntityState.Modified;
    
    foreach (var communic in donor.Communications)
    {
    	db.Entry(communic).State = communic.Id == 0 ? EntityState.Added : EntityState.Modified;
    }
    foreach (var categ in donor.Categories)
    {
    	db.Entry(categ).State = categ.Id == 0 ? EntityState.Added : EntityState.Modified;
    }
    db.Entry(donor).State = EntityState.Modified;
    await db.SaveChangesAsync();
    return donorVM;
    

    כנראה ששורה 11 זורקת את השגיאה, אם כי בלעדיה אני מקבל את השגיאה הבאה:

    Saving or accepting changes failed because more than one entity of type 'ContactApp.DAL.Model.Address' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration.

    ולמיטב זכרוני כדי לפתור זאת הוספתי את שורה 11, דהיינו יצרתי מופע חדש של הDB והכל בא על מקומו בשלום.
    אבל כנראה שלא...
    אשמח לשמוע מה הטעות שלי ואיך ניתן לתקן זאת..
    תודה רבה רבה לכולם מראש!!

    פורסם במקור בפורום CODE613 ב14/11/2017 01:39 (+02:00)

    תגובה 1 תגובה אחרונה
    0
    • dovidD מנותק
      dovidD מנותק
      dovid ניהול
      כתב ב נערך לאחרונה על ידי
      #2

      השגיאה הראשונה הגיונית מאוד, אתה טען מDB אחד, משאיר אותו חי (הוא לא עובר Dispose) ומחיל Stateים לDB אחר.

      השגיאה השניה פחות מובנת לי. זה נראה שיש מפתח ראשי ידני, או שדה עם אילוץ ייחודיות.

      מה בעצם הקלט של המשתמש שלכן אתה עושה שמירה כ"כ ענפה, עריכה או הוספה של קטגוריות, ו/או comminic?

      פורסם במקור בפורום CODE613 ב14/11/2017 07:40 (+02:00)

      מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

      בכל נושא אפשר ליצור קשר dovid@tchumim.com

      תגובה 1 תגובה אחרונה
      2
      • A מנותק
        A מנותק
        avr416
        כתב ב נערך לאחרונה על ידי
        #3

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

        בכל אופן, למיטב ידיעתי הטבלה מחזיקה מפתח ראשי שנוצר אוט', ולכן אני לא מבין מה השגיאה הזאת רוצה ממני.
        כמו כן, למיטב ידיעתי זה עבד עד עכשיו, ואתמול הוספתי ספריה של elmah לפרוייקט, ועדכנתי את הגרסה של האנטיטי, ואז פתאום זה התחיל לקרות. הסרתי את elmah ושינמכתי גרסה וזה לא עוזר.. אז כנראה זה לא קשור :shock:

        אין לי מושג מה לעשות..

        פורסם במקור בפורום CODE613 ב14/11/2017 09:00 (+02:00)

        תגובה 1 תגובה אחרונה
        0
        • dovidD מנותק
          dovidD מנותק
          dovid ניהול
          כתב ב נערך לאחרונה על ידי
          #4

          יש מצב שאתה מעלה את גוף המתודה MapAllObjUIToDAL?
          אגב, הref פה לכאורה מיותר כי זה בכל מקרה reference type.

          פורסם במקור בפורום CODE613 ב14/11/2017 09:22 (+02:00)

          מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

          בכל נושא אפשר ליצור קשר dovid@tchumim.com

          תגובה 1 תגובה אחרונה
          1
          • A מנותק
            A מנותק
            avr416
            כתב ב נערך לאחרונה על ידי
            #5

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

            Standard disconnectedStandard = null;
            
            using (var context = new SchoolDBEntities())
            {
                context.Configuration.ProxyCreationEnabled = false;
            
                disconnectedStandard = context.Standards.Where(s => s.StandardId == 58).Include(s => s.Teachers).FirstOrDefault<Standard>();
            }
            //Update Standard in disconnected mode
            disconnectedStandard.StandardName = "Edited Standard Name";
                        
            //Update teachers collection by editing first teacher and adding new teacher
            disconnectedStandard.Teachers.ElementAt(0).TeacherName = "Edited Teacher Name";
            disconnectedStandard.Teachers.Add(new Teacher() { TeacherName = "New Teacher", StandardId = disconnectedStandard.StandardId });
            
            using (var newContext = new SchoolDBEntities())
            {
                //mark standard based on StandardId
                newContext.Entry(disconnectedStandard).State = disconnectedStandard.StandardId == 0 ? EntityState.Added : EntityState.Modified;
            
                //mark teacher based on StandardId
                foreach (Teacher tchr in disconnectedStandard.Teachers)
                    newContext.Entry(tchr).State = tchr.TeacherId == 0 ? EntityState.Added : EntityState.Modified;
                            
                            
                newContext.SaveChanges();
            }
            

            כן, זה גוף המתודה:

            public static U MapAllObjUIToDAL<T,U>(T objUI,ref U objDAL)
                    {
                        
                        var mapper = reverseConfig.CreateMapper();
            
                        mapper.Map<T,U>(objUI,objDAL);
                     
                        return objDAL;
                    }
            

            תודה רבה!

            פורסם במקור בפורום CODE613 ב14/11/2017 09:27 (+02:00)

            תגובה 1 תגובה אחרונה
            0
            • A מנותק
              A מנותק
              avr416
              כתב ב נערך לאחרונה על ידי
              #6

              אכן, הנקודה היא שלא עשיתי dispose

              הוספתי את השורות הבאות וזה עובד טוב!

              db.Dispose();
              db = new ContactModel();
              

              אם כי לא ברור לי מדוע צריך לאתחל אותו מחדש..

              פורסם במקור בפורום CODE613 ב14/11/2017 09:32 (+02:00)

              תגובה 1 תגובה אחרונה
              0
              • dovidD מנותק
                dovidD מנותק
                dovid ניהול
                כתב ב נערך לאחרונה על ידי
                #7

                ברור שזה יעבוד... אבל זה לא נכון!

                עכ"פ שתי השגיאות לדעתי קשורים לזה שיש יותר מAddress אחד, ואילו אתה מתייחס רק לראשון. אז ממה נפשך, אם זה אותו קונטקסט, אז יש בעיה של ניסיון שינוי הID (כי נעשה בו שינויים ע"י הMAP - הוא כנראה במצע SET גם למאפיינים זהים) ואם זה קונקסט חדש, הרי זה נחשב EntityState.Added, בעוד יש להם כבר ID קיים ולכן נעשה נסיון לשים איבר כפול בDB (ואם לא ביטלת את הישן יש גם בעיה של שתי קונטקסטים לאותו אלמנט).

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

                foreach (var a in donor.Addresses)
                	db.Entry(a).State = EntityState.Unchanged;
                

                עם איזה מחלקת mapper אתה משתמש?
                ושאלה שממש בוערת במקרה הזה, איך הmapper יודע מה שורה קיימת ומה חדשה בליסטים של הכתובות והקטגוריות??

                פורסם במקור בפורום CODE613 ב14/11/2017 09:42 (+02:00)

                מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

                בכל נושא אפשר ליצור קשר dovid@tchumim.com

                תגובה 1 תגובה אחרונה
                0
                • A מנותק
                  A מנותק
                  avr416
                  כתב ב נערך לאחרונה על ידי
                  #8

                  @דוד ל.ט.

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

                  foreach (var a in donor.Addresses)
                  	db.Entry(a).State = EntityState.Unchanged;
                  

                  אז לא... זה לא עובד :?
                  נותן עדיין את אותה השגיאה, למרות שאפי' הוספתי במחלקות של הDAL את האטריביוט

                  [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
                  

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

                  פורסם במקור בפורום CODE613 ב14/11/2017 20:23 (+02:00)

                  תגובה 1 תגובה אחרונה
                  0
                  • dovidD מנותק
                    dovidD מנותק
                    dovid ניהול
                    כתב ב נערך לאחרונה על ידי
                    #9

                    @avr416

                    זה נשמע לי כמו באג באנטיטי..

                    אתה כתבת את זה ברצינות?
                    @דוד ל.ט.

                    המילה באג נאמרת לדעתי ברוב המקרים כתירוץ לאי לקיחת אחריות על בעיה שלא מוצאים לה שורש (כתבתי על זה פה http://tchumim.com/post/8965).

                    תענה לי בקשר לmapper. כי החשד נופל עליו.
                    כמו"כ לפי החשבון שלי, גם הדרך שלך שעובדת היא לא עושה את העבודה בDB כמו שצריך, בדוק את זה.

                    פורסם במקור בפורום CODE613 ב14/11/2017 20:31 (+02:00)

                    מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

                    בכל נושא אפשר ליצור קשר dovid@tchumim.com

                    תגובה 1 תגובה אחרונה
                    0
                    • dovidD מנותק
                      dovidD מנותק
                      dovid ניהול
                      כתב ב נערך לאחרונה על ידי
                      #10

                      אהה, עוד שאלה, לפני השורה הראשונה של הקוד הראשון, מתרחש משהו עם המופע db?

                      פורסם במקור בפורום CODE613 ב14/11/2017 20:38 (+02:00)

                      מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

                      בכל נושא אפשר ליצור קשר dovid@tchumim.com

                      תגובה 1 תגובה אחרונה
                      0
                      • A מנותק
                        A מנותק
                        avr416
                        כתב ב נערך לאחרונה על ידי
                        #11

                        הDB הוא סטטי למחלקה, והפונקציה סטטית, ואני לא מאתחל אותו בכל קריאה.

                        public static class MapObjToUI
                            {
                                static Model db = new Model();
                        

                        כנ"ל הmapper הוא משתנה סטטי, של המחלקה:

                        static MapperConfiguration config = new MapperConfiguration(cfg => {
                                    cfg.CreateMap<Donor, DonorVM>();
                                    cfg.CreateMap<Address, ContactAddressVM>();
                                    cfg.CreateMap<Category, CategoryVM>();
                                    cfg.CreateMap<Communication, CommunicationVM>();
                                    cfg.CreateMap<Setting, SettingVM>();
                                });
                        

                        פורסם במקור בפורום CODE613 ב14/11/2017 21:34 (+02:00)

                        תגובה 1 תגובה אחרונה
                        0
                        • dovidD מנותק
                          dovidD מנותק
                          dovid ניהול
                          כתב ב נערך לאחרונה על ידי
                          #12

                          סטטי לDbContext ועוד בווב זה רעיון גרוע מאוד. אין ספק שהבעיה נעוצה בזה.
                          אם אין לך כח להצהיר (כשזה כמה וכמה מתודות), תצהיר ברמת הקונטרולר [u:wv98m2jv]לא סטטי[/u:wv98m2jv], ותממש בקונטרולר IDispsable ובמתודת Dispose תסגור את המופע של הקונטקסט.
                          להגיד שהבנתי את השגיאה? לא לגמרי.

                          פורסם במקור בפורום CODE613 ב14/11/2017 21:54 (+02:00)

                          מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

                          בכל נושא אפשר ליצור קשר dovid@tchumim.com

                          תגובה 1 תגובה אחרונה
                          0
                          • A מנותק
                            A מנותק
                            avr416
                            כתב ב נערך לאחרונה על ידי
                            #13

                            @דוד ל.ט.

                            סטטי לDbContext ועוד בווב זה רעיון גרוע מאוד. אין ספק שהבעיה נעוצה בזה.
                            אם אין לך כח להצהיר (כשזה כמה וכמה מתודות), תצהיר ברמת הקונטרולר [u:23k0yp2q]לא סטטי[/u:23k0yp2q], ותממש בקונטרולר IDispsable ובמתודת Dispose תסגור את המופע של הקונטקסט.
                            להגיד שהבנתי את השגיאה? לא לגמרי.

                            מזל שיש אותך!!
                            שיניתי.. אבל זה עדיין זורק את אותה השגיאה <!-- s:-) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":-)" title="מחייך" /><!-- s:-) -->

                            פורסם במקור בפורום CODE613 ב14/11/2017 21:57 (+02:00)

                            תגובה 1 תגובה אחרונה
                            0
                            • dovidD מנותק
                              dovidD מנותק
                              dovid ניהול
                              כתב ב נערך לאחרונה על ידי
                              #14

                              @avr416

                              @דוד ל.ט.
                              סטטי לDbContext ועוד בווב זה רעיון גרוע מאוד. אין ספק שהבעיה נעוצה בזה.

                              אם אין לך כח להצהיר (כשזה כמה וכמה מתודות), תצהיר ברמת הקונטרולר [u:3s3pc33d]לא סטטי[/u:3s3pc33d], ותממש בקונטרולר IDispsable ובמתודת Dispose תסגור את המופע של הקונטקסט.
                              להגיד שהבנתי את השגיאה? לא לגמרי.

                              מזל שיש אותך!!
                              שיניתי.. אבל זה עדיין זורק את אותה השגיאה <!-- s:-) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":-)" title="מחייך" /><!-- s:-) -->

                              טוב כעת תורך לענות על השאלות האחרות.

                              פורסם במקור בפורום CODE613 ב14/11/2017 21:58 (+02:00)

                              מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

                              בכל נושא אפשר ליצור קשר dovid@tchumim.com

                              תגובה 1 תגובה אחרונה
                              0
                              • A מנותק
                                A מנותק
                                avr416
                                כתב ב נערך לאחרונה על ידי
                                #15

                                טוב, אז כפי שדוד העריך הבעיה היא בשילוב של הmapper (במקרה שלנו השתמשתי בספרייה automapper) עם הORM - דהיינו ה entityframework.

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

                                בקישור הנ"ל יש מאמר נפלא בנוגע בדיוק לבעיה הזאת, והוא ממליץ לא להשתמש בmapper במצבים כאלה, אלא למפות את האובייקטים בעצמך, וזה אכן מה שעשיתי, ופתר לי את הבעיות.

                                תודה לדוד על העזרה!

                                פורסם במקור בפורום CODE613 ב14/11/2017 23:32 (+02:00)

                                תגובה 1 תגובה אחרונה
                                1

                                בא תתחבר לדף היומי!
                                • התחברות

                                • אין לך חשבון עדיין? הרשמה

                                • התחברו או הירשמו כדי לחפש.
                                • פוסט ראשון
                                  פוסט אחרון
                                0
                                • דף הבית
                                • קטגוריות
                                • פוסטים אחרונים
                                • משתמשים
                                • חיפוש
                                • חוקי הפורום