开发者

Adding object to entityset is creating unwanted new DB row (many-to-many). Create relationship with existing object?

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 inst开发者_如何学Cances 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?


It doesn't matter if you set TAgId to existing value or not. EF is stupid - it doesn't do any Upsert / Merge for you. It doesn't check if the same entity exists and if TagId is auto generated in the database it even throw away your value once you call SaveChanges.

What you have to do? You must manually tell EF that Tag is not a new entity.

Try either:

Data.Shift s = new Data.Shift();
context.Shifts.AddObject(s);  // Add a new shift

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,
     };
     context.Tags.Attach(Tag); // Attach an existing tag
     s.Tags.Add(dt);
 }
 context.SaveChanges();

or

Data.Shift s = new Data.Shift();
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);
 }

 context.Shifts.AddObject(s);
 // Now shift and all tags are added
 // Change the state of each tag to unchanged
 foreach (var tag in s.Tags)
 {
     context.ObjectStateManager.ChangeEntityState(tag, EntityState.Unchanged);
 }
 context.SaveChanges();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜