views:

251

answers:

3

I have an Entity Framework v1 project. I have two entities (Roles and Permissions), which have a many-to-many relationship with each other. I pass in a object to be saved (through a WCF call, I do not create it from a context myself), which has new entries in the many-to-many relationship.

I use "context.ApplyPropertyChanges" to update the record with the new properties. I know that this does not update relationships though. I attempt to either do a ChildCollection.Add(relatedObject); or ChildCollection.Attach(relatedObject).

When I use the "Add" method, I get the error that: The object cannot be added to the ObjectStateManager because it already has an EntityKey. Use ObjectContext.Attach to attach an object that has an existing key.

When I use the "Attach" method, I get the error that: The object cannot be added to the ObjectStateManager because it already has an EntityKey. Use ObjectContext.Attach to attach an object that has an existing key.

I am getting quite frustrated, and I think I can hear the Entity Framework laughing at me.

Does anyone know how I can resolve this?

MyRole x = context.Roles.FirstOrDefault(a => a.RoleId == this.RoleId);

context.ApplyPropertyChanges("Roles", this);
foreach (MyPermission p in this.Permissions)
{
     x.Permissions.Add(p);
    //  ^ or v
     x.Permissions.Attach(p);
}
context.SaveChanges();

Thanks.

A: 

You are using multiple ObjectContexts concurrently (the variable context and whereever this came from). Don't do that. It will only make things very difficult for you. Use one ObjectContext at a time.

I can give more specific advice if you show more code.

Craig Stuntz
the context of "this" is automatically created by the WCF generated code. Is there any way to deal with that?Thanks.
Sako73
It would be best to use that context instead of making a new one. Again, hard to say without seeing the code.
Craig Stuntz
A: 

I suspect you are getting the errors because the ObjectContext thinks you are trying to add a new entity but finds it already has a EntityKey. I use the AttachTo method of the ObjectContext to attach my already existing entities to their EntitySet. I have had results generating my entities from stubs or hitting the database. This way when you add the entity to the navigation property on your entity, the ObjectContext finds the entity in it's EntitySet and knows it is an existing entity and not a new one. I don't know if this is clear. I could post some code if it would help. As Mr Stuntz said in his answer, posting more of your code would help.

DaveB
A: 

Wow. After 20 or so straight hours on this problem, I'm starting to hate the Entity Framework. Here is the code that appears to be working currently. I would appreciate any advice on how to make this more streamlined.

I did rework the WCF service so that there is only the one data context. Thanks Craig.

Then I had to change the code to the following:

MyRole x = context.Roles.FirstOrDefault(a => a.RoleId == this.RoleId);

if (x == null) // inserting
{
    MyApplication t = this.Application;
    this.Application = null;
    context.Attach(t);
    this.Application = t;
}
else // updating
{
    context.ApplyPropertyChanges("Roles", this);
    x.Permissions.Load();

    IEnumerable<Guid> oldPerms = x.Permissions.Select(y => y.PermissionId);
    List<MyPermission> newPerms = this.Permissions.Where(y => !oldPerms.Contains(y.PermissionId)).ToList();
    IEnumerable<Guid> curPerms = this.Permissions.Select(y => y.PermissionId);
    List<MyPermission> deletedPerms = x.Permissions.Where(y => !curPerms.Contains(y.PermissionId)).ToList();

    // new 
    foreach (MyPermission p in newPerms)
    {
        x.Permissions.Add(context.Permissions.First(z => z.PermissionId == p.PermissionId));
    }

    // deleted
    foreach (MyPermission p in deletedPerms)
    {
        x.Permissions.Remove(context.Permissions.First(z => z.PermissionId == p.PermissionId));
    }
}
Sako73