FloatingKiwi FloatingKiwi - 2 months ago 25
Vb.net Question

Issue using AsNoTracking with EntityFramework

I'm trying to do a deep clone of some entities. The approach mentioned in this article looks good but I run into errors. It suggests using AsNoTracking() to retrieve the entity and then to reinsert it into the context where it will cause an insert as it looks like a new object.

Here's my code:

Using ctxt As New ProductionDataEntities
Dim grade = ctxt.Grades.Include(Function(g) g.GradeWidths).AsNoTracking.First
ctxt.Grades.AddObject(grade)
ctxt.SaveChanges()
End Using


But when I run it I get:


An object with the same key already exists in the ObjectStateManager. The existing object is in the Modified state. An object can only be added to the ObjectStateManager again if it is in the added state.


And when I modify grade.Name it's EntityState changes to modified implying that it is being Tracked.

I'm using EF5 Db-First.

Alternatively I've tried cloning by detaching the grade and then reinserting it, this works but the GradeWidths don't get copied. As soon as I call detach the gradewidth count goes from 2 to 0.

Questions:


  1. Any idea why AsNoTracking isn't working and what I can do to fix this?

  2. Alternatively is there another approach someone can recommend for simple deep cloning?



Thanks.

---- additional info ----

I have 5 1-to-many relationships and eventually I'll want to clone from the top level all the way down. But I'm simplifying it to just look at the lowest level.


  • 1 Grade to many GradeWidths


Answer

Using ObjectContext

Using ObjectContext you can first attach the parent object and then change object state to added. Also for each child objects, change the object state to added. You even don't need AsNoTracking().

For example for a Category(1)↔(N)Product relation I used this code:

Using db As New SampleSystemEntities
    Dim c = db.Categories.Include(Function(x) x.Products).First
    db.Attach(c)
    db.ObjectStateManager.ChangeObjectState(c, EntityState.Added)
    For Each p As Product In c.Products
        db.ObjectStateManager.ChangeObjectState(p, EntityState.Added)
    Next
    db.SaveChanges()
End Using

Using DbContext

If you use DbContext every thing will work fine using your code:

Using db As New SampleSystemEntities
    Dim c = db.Categories.Include(Function(x) x.Products).AsNoTracking().First
    db.Categories.Add(c)
    db.SaveChanges()
End Using