
ADO.NET Entity Framework Model Example
Used Namespaces
First, import these namespaces in your project:using System; using System.Collections.Generic; using System.Data; using System.Data.Objects.DataClasses; using System.Diagnostics; using System.Linq; using System.Reflection;
Example of using the code in your project
This is an example of using the Clone() method in your code. The following example shows an iteration of Customers objects. Within the loop, the current Customer object makes a call to its Clone() member method which creates an exact copy of its caller object.The copy will be added tho the corresponding object context and at the end, all copied objects will be stored back in the datasource.
internal class Program
{
private static void Main(string[] args)
{
//Create an instance of the Object Context
var entities = new TestEntities();
//Get all customers from the datasource
var customers = from o in entities.Customers
select o;
//Iterate through the customers collection
foreach (var customer in customers)
{
//Create a deep copy of the customer object and add it to the Object Context
var myNewCustomer = (Customers) customer.Clone();
entities.AddToCustomers(myNewCustomer);
}
//Submit changes to the underlying datasource
entities.SaveChanges();
}
}
The Extension Method “Clone()” for the EntityObject Class
Everytime an (derived) object of the type “EntityObject” is accessed, the method “Clone()” will be available in the Intellisense of Visual Studio (see Screenshot).
Visual Studio Intellisense Appearance for Extension Methods
///
/// This class is used to store self references for
/// back tracking
///
public class SelfReferencesTracking
{
public string EntitySetName;
public EntityObject NewEntityObject;
public EntityKey OriginalKeys;
}
///
/// Extension method class for the EntityObject class
///
public static class EntityObjectExtension
{
//Enable tracking
private static readonly List _tracking =
new List();
///
/// These method makes a 1:1 copy of the original entity object
///
/// The original entity object /// The copied entity object
public static EntityObject Clone(this EntityObject entityObject)
{
//Get constructor for new object
var newEntityObject = entityObject.GetType().GetConstructor(
new Type[0]).Invoke(new object[0]);
_tracking.Add(new SelfReferencesTracking
{
EntitySetName = entityObject.EntityKey.EntitySetName,
OriginalKeys = entityObject.EntityKey,
NewEntityObject = (EntityObject)newEntityObject
});
//Copy all properties and its values of the given type
var properties = entityObject.GetType().GetProperties();
foreach (var property in properties)
{
try
{
var propertyValue = property.GetValue(entityObject, null);
PropertyInfo myProperty = property;
if (entityObject.EntityKey.EntityKeyValues.Where(x => x.Key == myProperty.Name).Count() == 0)
{
//Ignore all properties of these types
if (property.PropertyType != typeof(EntityKey) &&
property.PropertyType != typeof(EntityState) &&
property.PropertyType != typeof(EntityReference<>))
{
//Check, if the property is a complex type (collection), in that
//case, some special calls are necessary
if (property.GetCustomAttributes(
typeof(EdmRelationshipNavigationPropertyAttribute), false).Count() == 1)
{
//Check for self referencing entities
if (propertyValue.GetType() == entityObject.GetType())
{
//Get the self referenced entity object
var selfRefrencedEntityObject =
(EntityObject)property.GetValue(entityObject, null);
//This variable is used to store the new parent entity objects
EntityObject newParentEntityObject = null;
//This loops might be replaced by LINQ queries... I didn't try that
foreach (
var tracking in
_tracking.Where(
x =>
x.EntitySetName == selfRefrencedEntityObject.EntityKey.EntitySetName)
)
{
//Check, if the key is in the tracking list
foreach (
var newKeyValues in selfRefrencedEntityObject.EntityKey.EntityKeyValues)
{
//Iterate trough the keys and values
foreach (var orgKeyValues in tracking.OriginalKeys.EntityKeyValues)
{
//The key is stored in the tracking list, which means, this is
//the foreign key used by the self referencing property
if (newParentEntityObject == null)
{
if (orgKeyValues.Key == newKeyValues.Key &amp;&amp;
orgKeyValues.Value == newKeyValues.Value)
{
//Store the parent entity object
newParentEntityObject = tracking.NewEntityObject;
}
}
else
{
break;
}
}
}
}
//Set the value to the new parent entity object
property.SetValue(
newEntityObject,
newParentEntityObject, null);
}
else
{
//Entity collections are always generic
if (propertyValue.GetType().IsGenericType)
{
//Don't include self references collection, e.g. Orders1, Orders2 etc.
//Check for equality of the types (string comparison)
if (!propertyValue.GetType().GetGenericArguments().First().FullName.Equals(
entityObject.GetType().FullName))
{
//Get the entities of the given property
var entities =
(RelatedEnd)property.GetValue(entityObject, null);
//Load underlying collection, if not yet done...
if (!entities.IsLoaded) entities.Load();
//Create a generic instance of the entities collection object
var t = typeof(EntityCollection<>).MakeGenericType(
new[] { property.PropertyType.GetGenericArguments()[0] });
var newEntityCollection = Activator.CreateInstance(t);
//Iterate trough the entities collection
foreach (var entity in entities)
{
//Add the found entity to the dynamic generic collection
var addToCollection = newEntityCollection.GetType().GetMethod("Add");
addToCollection.Invoke(
newEntityCollection,
//new object[] {(EntityObject) entity});
new object[] { Clone((EntityObject)entity) });
}
//Set the property value
property.SetValue(
newEntityObject,
newEntityCollection,
null);
}
}
}
}
else
{
//Common task, just copy the simple type property into the new
//entity object
property.SetValue(
newEntityObject,
property.GetValue(entityObject, null), null);
}
}
}
}
catch (InvalidCastException ie)
{
//Hmm, something happend...
Debug.WriteLine(ie.Message);
continue;
}
catch (Exception ex)
{
//Hmm, something happend...
Debug.WriteLine(ex.Message);
continue;
}
}
return (EntityObject)newEntityObject;
}
}
Features
- Support for copying entity objects from top to the bottom (copying of all children and their values)
- Support for copying self-referenced entity objects (original relations will be tracked in an internal tracking list and copied entity objects will have the same relationship to the new parent entity object)
- Simple access because it’s an extension methods, no parameters are required
Pending Tasks
As mentioned above, this code is the first try to implement Clone() functionaity into the ADO.NET Entity Framework. I tested it just with the example database model above (up to 3 Tables) for seeing, if it’s gonna work or not. Pending tasks are among others:- Support for bottom-up relationships like child entities containing foreign keys to other (upper) entities (not yet tested)

HI,
this is a great example, thanks a lot!
Apparently however, your code won’t copy “simple references” to other entities, i.e. 1:1 relations.
Assuming that customer has a new relation to a sales contact of type “person”, the cloned customer object will still have a null-reference to the person-entity.
I’ve tried to figure out, how to do it, but wasn’t successful at all.
How would you try?
Would you deal with the auto-generated “reference properties” instead of the direct ones?
(I mean, property “SalesPersonReference” instead of “SalesPerson” in this example)
Thanks for any idea…
Zaengi
Thanks for the useful code.
I tried with foreign key references: the entity itself gets ignored, and the reference property throws this error at line 155:
“The EntityReference has already been initialized. InitializeRelatedReference should only be used to initialize a new EntityReference during deserialization of an entity object.”
But I might have messed up converting to VB.
An update to include these would be great!
Guy
Suggestion for handling foreign key references – replace line 153-157 with this:
if (propertyValue.GetType.BaseType.Name == “EntityReference”) {
//Simply copy the EntityKey to the new entity object’s EntityReference
((EntityReference)property.GetValue(newEntityObject, null)).EntityKey = ((EntityReference)property.GetValue(entityObject, null)).EntityKey;
}
else
{
//Common task, just copy the simple type property into the new entity object
property.SetValue(
newEntityObject,
property.GetValue(entityObject, null), null);
}
Thanks to URMANET for the original code and also to GuyB for the suggestion on handling foreign key references. Worked well for me!
Can you suggest how to clone the child objects associated with a parent entity ? My parent entity is cloned successfully but the children associated with it are not ?