0

I am trying to copy an object (Parent) and their relationships (Children1, Children2, Children3 and Children4), creating a new id for each of them in the database but it still fails. Is there any method that can do this?

Below is the structure of objects and their relationships. Please, I need a lot to someone help me.

public class Parent
{
    [PrimaryKey]
    public long IdParent {get; set;}
    public string Description {get; set;}
    public string OtherValue {get; set;}

    public virtual ICollection<Children1> Childrens1 {get; set;}
}

public class Children1
{
    [PrimaryKey]
    public long IdParent {get; set;}
    [PrimaryKey]
    public long IdChildren1 {get; set;}
    public string Description {get; set;}

    public virtual Parent Parent {get; set;}
    public virtual ICollection<Children1> Childrens1 {get; set;}
}

public class Children2
{
    [PrimaryKey]
    public long IdParent {get; set;}
    [PrimaryKey]
    public long IdChildren1 {get; set;}
    [PrimaryKey]
    public long IdChildren2 {get; set;}
    public string Description {get; set;}

    public virtual Children1 Children1 {get; set;}
}

public class Children3
{
    [PrimaryKey]
    public long IdParent {get; set;}
    [PrimaryKey]
    public long IdChildren1 {get; set;}
    [PrimaryKey]
    public long IdChildren3 {get; set;}
    public string Description {get; set;}

    public virtual Children1 Children1 {get; set;}
    public virtual ICollection<Children4> Childrens4 {get; set;}
}

public class Children3
{
    [PrimaryKey]
    public long IdParent {get; set;}
    [PrimaryKey]
    public long IdChildren1 {get; set;}
    [PrimaryKey]
    public long IdChildren3 {get; set;}
    [PrimaryKey]
    public long IdChildren4 {get; set;}
    public string Description {get; set;}

    public virtual Children3 Children3 {get; set;}
}

enter image description here

GustavoZafra
  • 335
  • 1
  • 2
  • 11
  • Could you provide us the code you tried to copy the entities with? – Jakub Jankowski Sep 30 '16 at 13:28
  • 1
    Retrieve your object graph with .AsNoTracking() then save it. http://stackoverflow.com/questions/15308747/entity-framework-5-deep-copy-clone-of-an-entity – Steve Greene Sep 30 '16 at 13:30
  • I am not a fan of your schema, it seems very rigid and not easy to extend the relationships past a certain point. Why not use a single table with a recursive relationship, ie. a Node structure? – Igor Sep 30 '16 at 13:31
  • I did it by serializing my object to json, deserializing it again. Just set the virtual members to [JsonIgnore] and added the parent to my context. worked for me – Matthias Burger Sep 30 '16 at 13:33
  • @JakubJankowski I tried several possible ways, including using the AsNoTracking () method did not work for me. – GustavoZafra Sep 30 '16 at 14:07
  • @SteveGreene I tried using the AsNoTracking () method but the Parent object it is inserted with only one level (in this case the Children1), it simply ignores the children's children – GustavoZafra Sep 30 '16 at 14:09
  • @MatthiasBurger Could you provide me an example of this in code? – GustavoZafra Sep 30 '16 at 14:10
  • @Igor It is not possible to make nodes because each table represents a different structure and in my scenario would not work. – GustavoZafra Sep 30 '16 at 14:12
  • @GustavoZafra everything you need is here: http://www.newtonsoft.com/json/help/html/serializingjson.htm . 10 minutes to read, 10 mins to code... – Matthias Burger Sep 30 '16 at 14:13
  • @MatthiasBurger The problem is that I need it to make the insertion of the parent object and their children as well, both as a copy. With JSON IGNORE it does not bring the children on the deserializer. – GustavoZafra Sep 30 '16 at 14:40
  • You're navigation properties are virtual so the children are lazy loaded. Use context.Parents.Include(e => e.Childrens1.Select(l1 => l1.Childrens2)) etc. See https://msdn.microsoft.com/en-us/library/gg671236%28v=vs.103%29.aspx#Anchor_1 – Steve Greene Sep 30 '16 at 14:43
  • Also, your sample models don't jive with the picture - Children1 should have a collection of Children2 and a collection of Children3. – Steve Greene Sep 30 '16 at 14:46
  • @GustavoZafra so check with reflection for children and deserialize them? add the children first to your context, get the ids and then set them in their related parent object? – Matthias Burger Sep 30 '16 at 14:54

2 Answers2

1

This is how I would approach this. Retrieve all parent-children from context with no tracking and add them back to context for cloning.

(I'm just showing sample code based of your entity diagram, as your entity model classes are not matching with it.)

public Item DeepClone(Parent item)
{
    Parent itemClone = db.Parents
        .Include(i => i.Childrens1.Select(c => c.Childrens2 ))
        .Include(i => i.Childrens3.Select(c => c.Childrens4 ))
        .AsNoTracking()
        .FirstOrDefault(i => i.IdParent == item.IdParent);

    db.Items.Add(itemClone);
    db.SaveChanges();
    return itemClone;
}
Cinchoo
  • 6,088
  • 2
  • 19
  • 34
0

The best thing to do in this case is to detach the object from context and then reinserting it, but the only problem with this approach is that detaching a parent object will not detach the related objects, you have to explicitly detach all the relative objects and then re insert them to make their clones

context.Detach(object);
context.SaveChanges(object);
context.Entry(object).State = EntityState.Added;
context.SaveChanges();
Riaz Raza
  • 382
  • 1
  • 14