Manish Mishra Manish Mishra - 2 years ago 90
C# Question

Cloning Object with many-to-many relationship in EntityFramework

All I want is just to create an exact copy of an object.

I have a class

public class Project
public int Id { get; set; }
public String Name { get; set; }

//navigational fields..
public virtual List<BusinessRequirement> BusinessRequirements { get; set; }

and another

public class BusinessRequirement
public int Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public virtual List<Project> Projects { get; set; }

so somewhere I've configured the many-to-many relationship b/w
like this:

HasMany(s => s.BusinessRequirements)
.WithMany(s => s.Projects)
.Map(m =>


and also I've made my dbcontext static i.e.

public static class DataLayer
public static MyDbContext db;

now, all m doing is, trying to make a copy of an object of

public Project Clone(Project source)

Project target = new Project();
target.Name = source.Name;
// target = source;

target.BusinessRequirements = new List<BusinessRequirement>();
foreach(BusinessRequirement br in source.BusinessRequirements)
BusinessRequirement nbr = DataLayer.Get<BusinessRequirement>(s=>s.Id=br.Id).SingleOrDefault();

//target.BusinessRequirements = source.BusinessRequirements;

//target.BusinessRequirements = new List<BusinessRequirement>();
//foreach(BusinessRequirement br in source.BusinessRequirements)
// BusinessRequirement nbr = br;
// if(nbr!=null)
// target.BusinessRequirements.Add(nbr);

return target;

none of the four methods work properly.

the one which is closest to working is 2, but a strange thing happens.
Now, If i add any BusinessRequirements to
Original Project
, it also gets added to
Clonned One
and vice-versa, same goes for deletion.

Somehow, entityframework is treating both the projects as one. Though this behavior occurs only in many-to-many related navigational properties.

Why EntityFramework is behaving like this???. What am I missing? please help..

Its been almost a day, but I cannot get it to work.

I have tried this, this, this and this but they didn't work either..

Answer Source

You can use the fact that adding an object to a context changes the state of any child objects in its object graph to Added:

Project proj;
using (var db = new MyDbContext())
    // Fetch a detached project and populate its BusinessRequirements.
    proj = db.Projects.AsNoTracking().Include(p => p.BusinessRequirements)
             .First(p => p.Id == source.Id);

By fetching the source project with AsNoTracking the context does not add it to its change tracker and the next line db.Projects.Add(proj); considers the project and its adhering child objects as brand new.

Silently, I renounced your strategy to work with one static context. It's a different topic, but you should not do that. Contexts are supposed to have a short life span.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download