Entity Framework 5 deep copy / clone object

I am using Entity Framework 5 ( DBContext ) and I am trying to find a better way to deep copy an object (i.e. copy an object and all related objects) and then save the new objects to the database. How can i do this? I have studied extension methods such as CloneHelper , but I'm not sure if it applies to DBContext .

+67
entity-framework-5 dbcontext
Mar 09 '13 at 8:25
source share
4 answers

One cheap easy way to clone an object is to do something like this:

 var originalEntity = Context.MySet.AsNoTracking() .FirstOrDefault(e => e.Id == 1); Context.MySet.Add(originalEntity); Context.SaveChanges(); 

the trick here is AsNoTracking () - when you load such an object, your context does not know about it, and when you call SaveChanges, it will consider it as a new object.

If MySet has a link to MyProperty and you need a copy of it, just use Include :

 var originalEntity = Context.MySet.Include("MyProperty") .AsNoTracking() .FirstOrDefault(e => e.Id == 1); 
+120
Mar 10 '13 at 12:51 on
source share

Here is another option.

I prefer it in some cases because it does not require you to specifically run a query in order to clone the data. You can use this method to create entity clones that you have already received from the database.

 //Get entity to be cloned var source = Context.ExampleRows.FirstOrDefault(); //Create and add clone object to context before setting its values var clone = new ExampleRow(); Context.ExampleRows.Add(clone); //Copy values from source to clone var sourceValues = Context.Entry(source).CurrentValues; Context.Entry(clone).CurrentValues.SetValues(sourceValues); //Change values of the copied entity clone.ExampleProperty = "New Value"; //Insert clone with changes into database Context.SaveChanges(); 

This method copies the current values โ€‹โ€‹from the source to the newly added row.

+21
Feb 12 '14 at 13:41
source share

This is a general extension method that allows you to generate cloning.

You need to extract System.Linq.Dynamic from nuget.

  public TEntity Clone<TEntity>(this DbContext context, TEntity entity) where TEntity : class { var keyName = GetKeyName<TEntity>(); var keyValue = context.Entry(entity).Property(keyName).CurrentValue; var keyType = typeof(TEntity).GetProperty(keyName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).PropertyType; var dbSet = context.Set<TEntity>(); var newEntity = dbSet .Where(keyName + " = @0", keyValue) .AsNoTracking() .Single(); context.Entry(newEntity).Property(keyName).CurrentValue = keyType.GetDefault(); context.Add(newEntity); return newEntity; } 

The only thing you need to implement is the GetKeyName method. It can be anything from return typeof(TEntity).Name + "Id" to return the first guid property or return the first property marked with DatabaseGenerated(DatabaseGeneratedOption.Identity)] .

In my case, I already tagged my classes [DataServiceKeyAttribute("EntityId")]

  private string GetKeyName<TEntity>() where TEntity : class { return ((DataServiceKeyAttribute)typeof(TEntity) .GetCustomAttributes(typeof(DataServiceKeyAttribute), true).First()) .KeyNames.Single(); } 
+1
Oct 27 '15 at 7:01
source share

I had the same issue in the Entity Framework Core where deep cloning involves several steps when children are loading lazily. One way to clone an entire structure is as follows:

  var clonedItem = Context.Parent.AsNoTracking() .Include(u => u.Child1) .Include(u => u.Child2) // deep includes might go here (see ThenInclude) .FirstOrDefault(u => u.ParentId == parentId); // remove old id from parent clonedItem.ParentId = 0; // remove old ids from children clonedItem.Parent1.ForEach(x => { x.Child1Id = 0; x.ParentId= 0; }); clonedItem.Parent2.ForEach(x => { x.Child2Id = 0; x.ParentId= 0; }); // customize entities before inserting it // mark everything for insert Context.Parent.Add(clonedItem); // save everything in one single transaction Context.SaveChanges(); 

Of course, there are ways to make universal functions for loading everything and / or resetting values โ€‹โ€‹for all keys, but this should make all the steps very clear and customizable (for example, donโ€™t clone everything for some children, skipping Include them).

0
Feb 04 '19 at 8:23
source share



All Articles