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 start
Using straight serialization, you can do this:
http://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/a967b44b-c85c-4afd-a499-f6ff604e2139/
Using Reflection, but with lots more code you can do this: http://msmvps.com/blogs/matthieu/archive/2008/05/31/entity-cloner.aspx
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.
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
To add a new row whose content is based on an existing row, follow these steps:
Here's an example:
var rabbit = db.Rabbits.First(r => r.Name == "Hopper");
db.Entry(rabbit).State = EntityState.Added;
rabbit.IsFlop = false;
db.SaveChanges();
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();
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.