Saturday, July 15, 2017

Entity Framework Woes

I started getting a new and horrifying Entity Framework error I had never seen before. Conflicting changes detected. This may happen when trying to insert multiple entities with the same key. It looked like it was due to me saving a parent and having it cascade to save children. Soooo, I took it upon myself to save parent, save child, reconstitute relationship. This was horrifying. My code went from Exhibit A:
        /// 
        /// Helper Method.  Updates Sections and Items
        /// 
        /// Agenda ID
        /// List of AgendaSections
        /// The Current User creating Sections and Items
        private void UpdateSectionsAndItems(int agendaId, IList<AgendaSection> agendaSections, IUser currentUser)
        {
            List<AgendaSectionItem> agendaSectionItems = new List<AgendaSectionItem>();

            int sectionNumber = 0;
            foreach (AgendaSection section in agendaSections)
            {
                section.Number = sectionNumber;
                section.AgendaId = agendaId;
                section.OwnerId = currentUser.UserId;
                if (section.AgendaSectionItems != null)
                {
                    int itemNumber = 0;
                    foreach (AgendaSectionItem item in section.AgendaSectionItems)
                    {
                        item.Number = itemNumber;
                        itemNumber++;
                        item.OwnerId = currentUser.UserId;
                        agendaSectionItems.AddRange(section.AgendaSectionItems);
                    }
                }
                sectionNumber++;
            }
            db.AgendaSections.AddRange(agendaSections);
            db.AgendaSectionItems.AddRange(agendaSectionItems);
            db.SaveChanges();
        }
To the following horrifying monstrosity:
        /// 
        /// Helper Method.  Updates Sections and Items
        /// 
        /// Agenda ID
        /// List of AgendaSections
        /// The current user
        private void UpdateSectionsAndItems(int agendaId, IList<AgendaSection> agendaSections, IUser currentUser)
        {            
            // This is a horrible workaround to deal with this mysterious error: 
            //   Conflicting changes detected. This may happen when trying to insert multiple entities with the same key.
            // That I get when I simply try to save parent (AgendaSection) and let it cascade down to the child (AgendaSectionItems).
            IDictionary<int, List<AgendaSectionItem>> tempItemDictionary = new Dictionary<int, List<AgendaSectionItem>>();
            int sectionNumber = 0;
            foreach (AgendaSection section in agendaSections)
            {
                section.Number = sectionNumber;
                section.AgendaId = agendaId;
                if (section.AgendaSectionItems != null)
                {
                    int itemNumber = 0;
                    foreach (AgendaSectionItem item in section.AgendaSectionItems)
                    {
                        item.Number = itemNumber;
                        itemNumber++;
                        item.OwnerId = currentUser.UserId;
                        if (tempItemDictionary.ContainsKey(section.Number.GetValueOrDefault()))
                        {
                            List<AgendaSectionItem> agendaSectionItems = tempItemDictionary[section.Number.GetValueOrDefault()];
                            agendaSectionItems.Add(item);
                        }
                        else
                        { 
                            List<AgendaSectionItem> agendaSectionItems = new List<AgendaSectionItem>();
                            agendaSectionItems.Add(item);
                            tempItemDictionary.Add(section.Number.GetValueOrDefault(), agendaSectionItems);
                        }
                    }
                }
                // More workaround
                section.AgendaSectionItems = null;
                sectionNumber++;
            }
            db.AgendaSections.AddRange(agendaSections);
            db.SaveChanges();

            // More workaround ... FML
            foreach (int i in tempItemDictionary.Keys)
            {
                IList<AgendaSectionItem> items = tempItemDictionary[i];
                AgendaSection agendaSection = agendaSections.First(s => s.Number == i);
                if (agendaSection != null)
                {
                    foreach (AgendaSectionItem item in items)
                    {
                        item.SectionId = agendaSection.SectionId;
                        if (agendaSection.AgendaSectionItems == null)
                        {
                            agendaSection.AgendaSectionItems = new List<AgendaSectionItem>();
                        }
                        agendaSection.AgendaSectionItems.Add(item);
                        db.AgendaSectionItems.Add(item);
                        db.SaveChanges();
                    }
                }
            }            
        }
When I finally got down to it, what I had done was accidentally mapped my primary key on a table as a foreign key in a completely incorrect mapping. So, I went and rolled back the monstrosity and will sleep better tonight.

No comments:

Post a Comment