【问题标题】:Updating a UserProfile and its Roles using Entity Framework使用实体框架更新 UserProfile 及其角色
【发布时间】:2013-06-06 00:43:02
【问题描述】:

我正在尝试找到一种方法来更新 UserProfile 实体以及分配给用户的角色列表。我已经写了下面的代码,但是它不起作用。

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;

}

这是工作单位

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 编辑方法

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

有人知道为什么这不起作用吗?或者可以在某个地方推荐一个实际有效的教程。一如既往,我们非常感谢任何帮助。

【问题讨论】:

  • 你正在改变实体状态,但你没有调用SaveChanges()。你会在函数之外这样做吗?
  • 是的,我使用了 UnitOfWork 模式,所以这个方法来自 UnitOfWork.UserProfileRepository.UpdateUserProfile。这个 UnitOfWork 拥有一个单独的上下文,该上下文被传递给每个使用的存储库,然后在该上下文上调用 SaveChanges。我已经编辑了上面的代码以显示控制器方法。

标签: entity-framework


【解决方案1】:

不要在控制器中创建新的UserProfile,而是从存储库中获取UserProfile,修改其字段,然后将其发送回UpdateUserProfile并调用Save

【讨论】:

  • 我一开始就是这么想的,但是如果其他用户同时更新了,那会改变 RowVersion 的 OriginalValue。 Entity Framework 在比较实体以评估是否发生并发冲突时使用(只读)OriginalValues
  • 您似乎面临两个不同的问题:1) 更新实体和 2) 并发策略。
【解决方案2】:

终于发现我一开始就完全错了。我根本没有改变关系。我已经包含了下面的代码,它允许我将父实体附加为已修改,然后根据需要将关系标记为添加和删除

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-14
    • 2011-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-02
    相关资源
    最近更新 更多