2013-06-06 2 views
0

Я пытаюсь найти способ, который позволит мне обновить объект UserProfile вместе со списком Ролей, которым назначен пользователь. Я написал код ниже, но он не работает.Обновление UserProfile и его ролей с использованием Entity Framework

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; 

} 

Вот 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); 
} 

} 
} 

... и вот метод HttpPost Edit

[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); 
    } 

Кто-нибудь есть какие-либо идеи, почему это не работает? Или может предложить учебник где-то, что действительно работает. Любая помощь, как всегда, очень ценится.

+0

Вы меняете состояние сущности вокруг, но вы не вызываете 'SaveChanges()'. Вы делаете это вне функции? – bcr

+0

Да, я использовал шаблон UnitOfWork, так что это метод из модуля UnitOfWork.UserProfileRepository.UpdateUserProfile. Этот UnitOfWork содержит один контекст, который передается в каждый использованный репозиторий, а затем вызывает SaveChanges в этом контексте. Я изменил код выше, чтобы показать метод контроллера. – MickySmig

ответ

0

Вместо создания нового UserProfile в контроллере, получить UserProfile из репозитория, изменить его поле, а затем отправить его обратно в UpdateUserProfile и вызвать Save.

+0

Это было то, о чем я думал сначала, но это изменит исходное значение RowVersion, если другой пользователь обновил это время. Entity Framework использует (только для чтения) OriginalValues, когда сравнивает сущности, чтобы оценить, произошло ли нарушение параллелизма. – MickySmig

+0

Кажется, что вы сталкиваетесь с двумя различными проблемами: 1) Обновление сущности и 2) Стратегия параллелизма. – Jasen

0

Наконец-то выяснилось, что в первую очередь это было неправильно. Я вообще не менял отношения. Я включил приведенный ниже код, который позволяет мне связать родительский объект как измененный, а затем пометить отношения как добавленные и удаленные по мере необходимости

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); 
    } 
}