I am long time reader - first time poster - and after countless hours of research on this Entity Framework issue, I felt like I needed some help. I'm new to C# and new to programming, so please bear with me.
I have a fairly simple many-to-many relationship in my data model with Web 2.0 style "Tags". Shifts have tags and users have tags.
I am pulling a shift from a cache. When I try to make a copy of a shift, copying over the shift details and tags from the cached copy, I do the following (simplified).
Data.Shift s = new Data.Shift();
/* copy over a bunch of stuff from the cached shift object. I'll spare the boring details */
foreach (var t in shift.Tags) { //shift object is a cached object
Data.Tag dt = new Data.Tag
{
TagID = t.TagID,
Name = t.Name,
OrgID = t.OrgID,
};
s.Tags.Add(dt);
}
Even though I have explicitly set the TagID in the new Data.Tag object, on SaveChanges() a new tag is inserted into the DB, rather than just creating a relationship on the Tag that already exists in the DB. TagID is a PK identity column
When I try the following code:
foreach (var t in shift.Tags){
s.Tags.Add(t)
}
It obviously fails because the shift was cached from a different object context than the current requests' context.
Any thoughts? As far as I can tell:
- Clearing the cache is not an option for me because of performance concerns -- I recognize that this whole issue would go away if I did this work within the same object context.
- Also, pulling the Data.Tag from the DB in the current context is not an option because of perf concerns.
This seems like a really easy thing I am trying to do...
Edit Ok -- I've tried updating my code with both solutions but I am running into trouble with both. Let's try the first one:
// ctx is grabbed up here from HttpContext.Current.Items
Data.Shift s = new Data.Shift();
/* copy over a bunch of stuff from the cached shift object. I'll spare the boring details */
foreach (var t in shift.Tags) { //shift object is a cached object
Data.Tag dt = new Data.Tag
{
TagID = t.TagID,
Name = t.Name,
OrgID = t.OrgID,
};
ObjectStateEntry entry;
ctx.ObjectStateManager.TryGetObjectStateEntry(t.EntityKey, out entry);
if (entry == null || entry.State == EntityState.Detached) {
ctx.Tags.Attach(t);
}
s.Tags.Add(dt);
}
This is throwing the following error:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
I am guessing that the reason I am getting is this error, is because the shift object and its tags are pulled out of a cache (obviously from different contexts). Thoughts?
SaveChanges? Where do you add the Shift to the context? Do you add or attach the new tags to the context explicitely? It's likely that attaching the tags to the context is missing which would explain that new tags are created, but just a guess...