Updating a UserProfile and its Roles using Entity Framework

妖精的绣舞 提交于 2020-01-06 07:14:10

问题


I'm trying to find a way that would allow me to update a UserProfile entity along with a list of Roles that the user is assigned to. I've written the code below, but it doesn't work.

public void UpdateUserProfile(UserProfile userProfile)
{
  context.Entry(userProfile).State = EntityState.Added;

  var databaseRoleIds = context.Roles
    .Where(r => r.UserProfiles
      .Any(u => u.UserId == userProfile.UserId))
      .Select(r => r.RoleId).ToList();

  var clientRoleIds = userProfile.Roles.Select(r => r.RoleId).ToList();

  var removedRoleIds = databaseRoleIds.Except(clientRoleIds).ToList();

  var addedRoleIds = clientRoleIds.Except(databaseRoleIds).ToList();

  var unchangedRoleIds = removedRoleIds.Union(addedRoleIds).ToList();

  foreach (var roleId in unchangedRoleIds)
  {
    var role = context.Roles.Find(roleId);
    context.Entry(role).State = EntityState.Unchanged;
  }

  foreach (var roleId in removedRoleIds)
  {
    userProfile.RemoveRole(context.Roles.Find(roleId));
  }

  foreach (var roleId in addedRoleIds)
  {
    userProfile.AddRole(context.Roles.Find(roleId));
  }

  context.Entry(userProfile).State = EntityState.Modified;

}

Here is the unitOfWork

namespace MvcWebsite.WorkUnits
{
public class WorkUnit : IWorkUnit, IDisposable
{
private MvcContext context = new MvcContext();
private RoleRepository roleRepository;
private UserProfileRepository userProfileRepository;

public IRoleRepository RoleRepository
{
  get
  {
    if (this.roleRepository == null)
    {
      roleRepository = new RoleRepository(context);
    }
    return roleRepository;
  }
}

public IUserProfileRepository UserProfileRepository
{
  get
  {
    if (this.userProfileRepository == null)
    {
      userProfileRepository = new UserProfileRepository(context);
    }
    return userProfileRepository;
  }
}

public void Save()
{
  context.SaveChanges();
}

private bool disposed = false;

protected virtual void Dispose(bool disposing)
{
  if (!this.disposed)
  {
    if (disposing)
    {
      context.Dispose();
    }
  }
  this.disposed = true;
}

public void Dispose()
{
  Dispose(true);
  GC.SuppressFinalize(this);
}

}
}

... and here is the HttpPost Edit method

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(UserProfileEditViewModel model)
    {
      try
      {
        if (ModelState.IsValid)
        {
          var clientUserProfile = new UserProfile();
          clientUserProfile.UserId = model.UserId;
          clientUserProfile.UserName = model.UserName;
          clientUserProfile.FirstName = model.FirstName;
          clientUserProfile.LastName = model.LastName;
          clientUserProfile.Email = model.Email;
          clientUserProfile.RowVersion = model.RowVersion;
          clientUserProfile.Roles = new List<Role>();
          foreach(var role in model.Roles)
          {
            if (role.Assigned)
            {
              clientUserProfile.Roles.Add(new Role
              {
                RoleId = role.RoleId,
                RoleName = role.RoleName,
                RowVersion = role.RowVersion,
              });
            }

          }
          unitOfWork.UserProfileRepository.UpdateUserProfile(clientUserProfile);
          unitOfWork.Save();
          return RedirectToAction("Details", new { id = clientUserProfile.UserId });

        }
      }
      catch (DataException ex)
      {
        ModelState.AddModelError("", "Unable to save changes.  Try again, and if the problem persists, see your system administrator.");
      }
      return View(model);
    }

Does anyone have any idea why this isn't working? Or could suggest a tutorial somewhere that actually works. Any help, as always, is greatly appreciated.


回答1:


Instead of creating a new UserProfile in your controller, get the UserProfile from the repository, modify its fields, then send it back to UpdateUserProfile and call Save.




回答2:


Finally found that I had it totally wrong in the first place. I wasn't changing the relationships at all. I've included the code below, which allows me to attach the parent entity as modified and then mark the relationships as added and deleted as required

public void UpdateUserProfile(UserProfile userProfile)
{
  context.Entry(userProfile).State = EntityState.Modified;
  var objectContext = ((IObjectContextAdapter)context).ObjectContext;

  foreach (var role in userProfile.Roles)
  {
    context.Entry(role).State = EntityState.Unchanged;
  }

  var databaseRoleIds = context.Roles
    .Where(r => r.UserProfiles
      .Any(u => u.UserId == userProfile.UserId))
      .Select(r => r.RoleId)
      .ToList();

  var clientRoleIds = userProfile.Roles.Select(r => r.RoleId).ToList();

  var removedRoleIds = databaseRoleIds.Except(clientRoleIds).ToList();

  var addedRoleIds = clientRoleIds.Except(databaseRoleIds).ToList();

  foreach (var roleId in removedRoleIds)
  {
    var role = context.Roles.Find(roleId);
    objectContext
      .ObjectStateManager
      .ChangeRelationshipState(userProfile, role, u => u.Roles, EntityState.Deleted);
  }

  foreach (var roleId in addedRoleIds)
  {
    var role = context.Roles.Find(roleId);
    objectContext
      .ObjectStateManager
      .ChangeRelationshipState(userProfile, role, u => u.Roles, EntityState.Added);
  }
}


来源:https://stackoverflow.com/questions/16952031/updating-a-userprofile-and-its-roles-using-entity-framework

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!