0

I try to find best solution to the problem while updating entity which has deep relationships. Because my entities are too complex and have deeper relationships, I simplified into this.

MainCategory - Category has one-to-many relationship and Category - SubCategory has also one-to-many relationship

public class MainCategory
{
    [Key]
    public int Id { get; set; }
    public string MainCategoryName { get; set; }

    public virtual ICollection<Category> Categories { get; set; }
}

public class Category
{
    [Key]
    public int Id { get; set; }
    public string CategoryName { get; set; }

    public virtual ICollection<SubCategory> SubCategories { get; set; }
}

public class SubCategory 
{
    [Key]
    public int Id { get; set; }
    public string SubCategoryName { get; set; }

    public Category Category { get; set; }
}

Here is how I handle the situation while updated or new MainCategory entity with child and grandchild records comes from somewhere.

public void AddOrUpdateMainCategory()
{
    using (var ctx = new MyContext())
    {
        // Gets MainCategory domain object.
        // Domain object has no id property because it does not come from (ctx.MainCategories)
        var mainCategory = GetMainCategory();

        var mainCategoryFromDb = ctx.MainCategory.Include(x => x.Categories.Select(y => y.SubCategories)).FirstOrDefault(x => someCondition());

        if (mainCategoryFromDb == null)
        {
            ctx.ShopParameterPeriodItems.Add(mainCategory);
        }

        // If mainCategoryFromDb is not null, mainCategory object should map to mainCategoryFromDb.
        else
        {
            ctx.SubCategories.RemoveRange(mainCategoryFromDb.Categories.SelectMany(x => x.SubCategories));
            ctx.Categories.RemoveRange(mainCategoryFromDb.Categories);
            ctx.MainCategories.Remove(mainCategoryFromDb);

            ctx.MainCategories.Add(mainCategory);
         }

         ctx.SaveChanges();
    }
}

Problems of code

  • Because updating mechanism is deleting old entity and its child and grandchild entities and adding a new one, Id value of database records are refreshed every time. This would be a big problem if any foreign key exists to MainCategory, Category, or SubCategory from different tables.
  • The first problem can be solved like that

        foreach (var category in mainCategoryFromDb.Categories)
        {
             foreach (var subCategory in category.SubCategories)
             {
                  // Set subCategory properties
             }
    
             // Set category properties
        }
    
        // Set mainCategoryFromDb properties
    

    This solves Id loss problem but as I wrote, entities are very complex. It would be hard to maintain and we do not know, for example, which category of mainCategory will update category of mainCategoryFromDb because mainCategory and its child and grandchild entities do not have Id property.

What I am looking for is a way to solve the problems.

dewe
  • 101
  • 2
  • 9

1 Answers1

0

Your problem is that you're working with disconnected entities, and so they are not monitored for changes by a DbContext. So, what you need to do is to track the changes yourself in the disconected scenario, and later on, when you attach them back to a DbContext, set the correct status for each entity according to the tracked changes.

There isn's a fiex solution for tracking the changes, but, to send the changes to the database you simply have to attach the root object to the context, and then set the status of each tracked entity.

Please see How to use DBContext.Add/Attach (using EF CodeFirst 4.1) with nested opbjects. This shows the basid way of attaching and setting status. Then you simply have to set different statuses, apart from Unchanged, which is shown in this Q&A.

Community
  • 1
  • 1
JotaBe
  • 38,030
  • 8
  • 98
  • 117
  • But I think, entity that will be attached must be an id attribute to match with a database record? My DTO objects do not have. – dewe Aug 28 '15 at 10:52