Cloning data on Entity Framework

Entity Framework

Entity Framework Problem Overview


I am creating software where user can create new product based on older product.

Now I need to make copying / cloning operations with Entity Framework. First I started writing like this:

foreach(sourcedata1 in table1)
{
... create new table
... copy data
... create Guid
... add
foreach(sourcedata2 in table2)
{
... create new table
... copy data
... create Guid
... add

   ... and so on

} }

Problem is that this not a nice way to do it. Is there any easy way clone information (except Guid that needs to be generated for new rows) or should I manually copy everything?

Other solution

You could also use EmitMapper or AutoMapper to do copying of the properties.

Entity Framework Solutions


Solution 1 - Entity Framework

To clone an Entity in Entity Framework you could simply Detach the entity from the DataContext and then re-add it to the EntityCollection.

context.Detach(entity);
entityCollection.Add(entity);

Update for EF6+ (from comments)

context.Entry(entity).State = EntityState.Detached;
entity.id = 0;
entity.property = value;
context.Entry(entity).State = EntityState.Added;
context.SaveChanges();

Solution 2 - Entity Framework

public static EntityObject Clone(this EntityObject Entity)
{
    var Type = Entity.GetType();
    var Clone = Activator.CreateInstance(Type);

    foreach (var Property in Type.GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.SetProperty))
    {
        if (Property.PropertyType.IsGenericType && Property.PropertyType.GetGenericTypeDefinition() == typeof(EntityReference<>)) continue;
        if (Property.PropertyType.IsGenericType && Property.PropertyType.GetGenericTypeDefinition() == typeof(EntityCollection<>)) continue;
        if (Property.PropertyType.IsSubclassOf(typeof(EntityObject)))  continue;

        if (Property.CanWrite)
        {
            Property.SetValue(Clone, Property.GetValue(Entity, null), null);
        }
    }

    return (EntityObject)Clone;
}

This is a simple method I wrote. It should work for most people.

Solution 3 - Entity Framework

To add a new row whose content is based on an existing row, follow these steps:

  1. Get an entity based on the starting row.
  2. Set the entry state for the entity to Added.
  3. Modify the entity.
  4. Save changes.

Here's an example:

var rabbit = db.Rabbits.First(r => r.Name == "Hopper");
db.Entry(rabbit).State = EntityState.Added;
rabbit.IsFlop = false;
db.SaveChanges();

Solution 4 - Entity Framework

If you want to create a copy of an entity for comparison later in your code execution, you can select the entity in a new db context.

If for example you are updating an entity, then later in the code you want to compare the updated and original entity:

var db = new dbEntityContext();
var dbOrig = new dbEntityContext();

var myEntity = db.tblData.FirstOrDefault(t => t.Id == 123);
var myEntityOrig = dbOrig.tblData.FirstOrDefault(t => t.Id == 123);

//Update the entity with changes
myEntity.FirstName = "Gary";

//Save Changes
db.SaveChnages();

At this point, myEntity.FirstName will contain "Gary" whilst myEntityOrig.FirstName will contain the original value. Useful if you have a function to log changes where you can pass in the updated and original entity.

Solution 5 - Entity Framework

A really short way of duplicating entities using generics (VB, sorry).
It copies foreign key values (external IDs) but doesn't load their related objects.

<Extension> _
Public Function DuplicateEntity(Of T As {New, Class})(ctx As myContext, ent As T) As T
    Dim other As New T 'T is a proxy type, but New T creates a non proxy instance
    ctx.Entry(other).State = EntityState.Added 'attaches it to ctx
    ctx.Entry(other).CurrentValues.SetValues(ent) 'copies primitive properties
    Return other
End Function

For instance:

newDad = ctx.DuplicateEntity(oDad)
newDad.RIDGrandpa ' int value copied
newDad.Grandpa    ' object for RIDGrandpa above, equals Nothing(null)
newDad.Children   ' nothing, empty

I don't know exactly how to reload Grandpa in this case.
This doesn't work:

ctx.SaveChanges()
ctx.Entry(newDad).Reload()

but really, no problem. I would rather assign Grandpa by hand if I need it.

newDad.Grandpa = oDad.Grandpa

EDIT: As MattW proposes in his comment, detaching and finding the new entity you get its children loaded (not collections).

ctx.Entry(newDad).State = EntityState.Detached
ctx.Find(newDad.RowId) 'you have to know the key name

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTx3View Question on Stackoverflow
Solution 1 - Entity FrameworkChrisNel52View Answer on Stackoverflow
Solution 2 - Entity FrameworkTomasiView Answer on Stackoverflow
Solution 3 - Entity FrameworkEdward BreyView Answer on Stackoverflow
Solution 4 - Entity FrameworkSausageFingersView Answer on Stackoverflow
Solution 5 - Entity FrameworkIvan Ferrer VillaView Answer on Stackoverflow