Remove a list of objects and add new ones efficiently using Entity Framework

asp.net-mvc business-logic entity-framework-6

Question

I'm taking into two multiselect lists into my Edit Action Post method along with a viewmodel. For each multiselect I want to loop through each object and remove what is not selected and add what is.

In this case, I'm adding and removing users from the project that are of a certain role type. Initially I was thinking db.SaveChages() on each iteration but that seems inefficient? Any suggestions for a better approach? Currently this doesn't work... Pardon if I'm way off base, this is my 4th week learning MVC. Thanks in advance!

   // POST: Projects/Edit
    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize(Roles = "Administrator")]
    public ActionResult Edit(ProjectEditViewModel vm, int ProjectStatusId)
    {
        if (ModelState.IsValid)
        {
            var project = db.Project.Find(vm.ProjectId);

            project.Name = vm.ProjectName;

            project.ProjectStatusId = ProjectStatusId;

            var users = db.Users.Where((u => u.Projects.Any(ui => ui.ProjectId == vm.ProjectId)));

            var currentDevs = users.Where(u => u.Roles.Any(ur => ur.RoleId == db.Roles.FirstOrDefault(r => r.Name == "Developer").Id));

            var currentPMs = users.Where(u => u.Roles.Any(ur => ur.RoleId == db.Roles.FirstOrDefault(r => r.Name == "Project_Manager").Id));

            if (currentDevs != null)
            {
                foreach (var cd in currentDevs)
                {
                    project.Users.Remove(cd);

                }                   
            }
            if (currentPMs != null)
            {
                foreach (var cpm in currentPMs)
                {
                    project.Users.Remove(cpm);

                }
            }

            if (vm.SelectedDevs != null)
            {
                foreach (var dev in vm.SelectedDevs)
                {
                    var developer = users.FirstOrDefault(a => a.DisplayName == dev);

                    project.Users.Add(developer);
                }
            }

            if (vm.SelectedPMs != null)
            {
                foreach (var pm in vm.SelectedPMs)
                {
                    var projMgr = users.FirstOrDefault(a => a.DisplayName == pm);

                    project.Users.Add(projMgr);
                }
            }

            db.Entry(project).State = EntityState.Modified;

            db.SaveChanges();

            return RedirectToAction("Details", new { id = vm.ProjectId });
        }

        return View(vm);
    }
1
0
5/4/2015 5:11:24 PM

Accepted Answer

Thought I'd swing back around and post my solution for 1 of the two role types. Same logic was applied to the other (1st solution to SO woot!!!)

var devRoleId = db.Roles.FirstOrDefault(r => r.Name == "Developer").Id;
            var users = db.Users.ToList();

            //currently assigned developers
            var currentDevs = (from p in project.Users
                               where p.Roles.Any(r => r.RoleId == devRoleId)
                               select p).ToList();

            // if the new list is null and old list is not null, remove the old list members
                if (vm.SelectedDevs == null)
                {
                    if(currentDevs != null)
                    {
                        foreach (var d in currentDevs)  
                        {
                            project.Users.Remove(d);
                        }
                    }
                }                

            //if the new list is not null 
                if (vm.SelectedDevs != null)   
                {
                    if (currentDevs == null) //if the old list is null, add the new list members
                   {
                       foreach(var nd in vm.SelectedDevs)
                       {
                           project.Users.Add(users.FirstOrDefault( u => u.DisplayName == nd));
                       }
                   }
                   else  //if the old list is not null, compare each new list member to old and if its new list member is truely new, add them
                   {
                        foreach(var nd in vm.SelectedDevs)
                        {
                            if(!currentDevs.Any(cd => cd.DisplayName == nd))
                            project.Users.Add(users.FirstOrDefault( u => u.DisplayName == nd));
                        }
                   }
                }
2
5/8/2015 6:29:38 PM

Popular Answer

This should work for you. You don't want to remove all the users and re-add them each time. That's going to cause a lot of problems. Instead, you remove only the ones that have been de-selected, and then add only the ones that have been newly-selected (did not exist in the list before).

var devRoleId = db.Roles.FirstOrDefault(r => r.Name == "Developer").Id;
var pmRoleId = db.Roles.FirstOrDefault(r => r.Name == "Project_Manager").Id;

// Remove de-selected devs
project.Users.Where(u => u.RoleId == devRoleId && !vm.SelectedDevs.Contains(u.DisplayName))
    .ToList().ForEach(u => project.Users.Remove(u));

// Add newly selected devs
var existingDevs = project.Users.Where(u => u.RoleId == devRoleId).Select(m => m.DisplayName);
db.Users.Where(u => vm.SelectedDevs.Exclude(existingDevs).Contains(u.DisplayName))
    .ToList().ForEach(u => project.Users.Add(u));

// Remove de-selected PMs
project.Users.Where(u => u.RoleId == pmRoleId && !vm.SelectedPMs.Contains(u.DisplayName))
    .ToList().ForEach(u => project.Users.Remove(u));

// Add newly selected PMs
var existingPMs = project.Users.Where(u => u.RoleId == pmRoleId).Select(m => m.DisplayName);
db.Users.Where(u => vm.SelectedPMs.Exclude(existingPMs).Contains(u.DisplayName))
    .ToList().ForEach(u => project.Users.Add(u));


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow