1

I have a simple table setup

User
- Id
- Name

Role
- Id
- Name

UserRole
- UserId
- RoleId

Using Fluent I have the following relationship declared

this.HasMany(t => t.Roles)
.WithMany(s => s.Users)
.Map(m =>
{
        m.ToTable("UserRole");
        m.MapLeftKey("UserId");
        m.MapRightKey("RoleId");
});

When I create a new User with multiple Role it adds them correctly in the Database. When I Update a User with Role's that don't already exist yet then it is OK.

I am having problems adding the following:

Existing Roles

Role A
Role B
Role C

I want to remove Role B thus leaving

Role A
Role C

I have tried a couple of things but I always end up with the "Additional information: Saving or accepting changes failed because more than one entity of type '...Role' have the same primary key value." or no deletion occurs at all.

Method 1

I have tried things like creating a method to delete all the Roles first then just adding the incoming Roles but for some reason it's maintaining the tracked changes and still sees the Roles that are deleted.

public ActionResult Edit(int userId, User user)
{
    // clear roles
    _userService.ClearRoles(userId);
    _unitOfWork.Save();

    // if I put a break here, I can see the roles being removed from the database


    // update user with new roles
    _userService.Update(id, user)
    _unitOfWork.Save();

}


// _userService.Update

public void Update(int userId, User user)
{
    User existingUser = Find(userId);
    if (existingUser != null)
    {
        existingUser.Roles = user.Roles;
        _userRepository.Update(existingUser);
    }
}

public void ClearRoles(int userId)
{
   User existingUser = GetUser(userId);

   if(existingUser != null)
   {
       existingUser.Roles.ToList().ForEach(f => existingUser.Roles.Remove(f));                
   }
}

Method 2

I tried to remove the Role objects but no Roles get deleted, nothing happens

 public ActionResult Edit(int userId, User user)
 {
        _userService.Update(id, user)
        _unitOfWork.Save();

 }


// _userService.Update

public void Update(int userId, User user)
{
    User existingUser = Find(userId);

    if (existingUser != null)
    {
        existingUser.Roles.ToList().ForEach(f => existingUser.Roles.Remove(f));
        existingUser.Roles = user.Roles;

        _userRepository.Update(existingUser);
    }
}

Any further ideas on how to resolve this?

fes
  • 2,465
  • 11
  • 40
  • 56
  • What is `userModel`, as in `userModel.Roles`? My first guess is that it doesn't have the roles in it that you expect it to. – Steve Ruble Aug 24 '14 at 12:45
  • sorry that should have read user.Roles. – fes Aug 24 '14 at 13:03
  • What does `_userRepository.Update` do? – Steve Ruble Aug 24 '14 at 13:10
  • It marks the User entity state as modified, then attaches itself to the DbSet waiting for a commit. – fes Aug 24 '14 at 13:16
  • Is it necessary to do either of those things, since you (presumably) obtained the `existingUser` instance from the DbSet in the first place? I'm wondering if manually setting the state to `Modified` is overwriting the `Deleted` state on the relationship between the `User` and the `Role`s you removed. – Steve Ruble Aug 24 '14 at 13:46
  • I don't quite get what you are saying. I will need to call the Update to update the User regardless if i've added a new role or deleted a role. All I want to do is delete all the roles, then just re-add the roles but it doesn't seem to work. Not sure what I'm missing. – fes Aug 24 '14 at 14:10
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/59888/discussion-between-steve-ruble-and-fes). – Steve Ruble Aug 24 '14 at 14:42

1 Answers1

0

Concering the error: "Saving or accepting changes failed because more than one entity of type '' have the same primary key value"...

This often occurs when a dbcontext, having several same objects orginated from a different db context, is flushed towards the database.

Example

  public void Save(PlcVariable plcVariable)
    {
        try
        {
            using (var context = new XBSDbDataContext())
            {
                plcVariable.PlcVariableMeasure.LineObjects // Plc variable has a selfreference that has a list of lineobject, that already has a line object with id = 1
                var lineobject =  new LineObjectService().GetById(1);//=> this line object is orginated from another Dbcontext.
                plcVariable.LineObjects.Add(lineobject); 
                context.SaveChanges(); // error occurs
                // EF will see the added line object as a different object, because it is coming from another dbcontext, than the same object(equal id's) that is already present.
            }

You can try to assure to load object with one dbContext.

free
  • 153
  • 1
  • 2
  • 18