Entity Framework 5 copia/clonación profunda de una entidad


Estoy usando Entity Framework 5 (DBContext) y estoy tratando de encontrar la mejor manera de copiar profundamente una entidad (es decir, copiar la entidad y todos los objetos relacionados) y luego guardar las nuevas entidades en la base de datos. ¿Cómo puedo hacer esto? He investigado el uso de métodos de extensión como CloneHelper, pero no estoy seguro de si se aplica a DBContext.

Author: Chris, 2013-03-09

3 answers

Una forma fácil y barata de clonar una entidad es hacer algo como esto:

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

El truco aquí es AsNoTracking() - cuando carga una entidad como esta, su contexto no lo sabe y cuando llama a SaveChanges, lo tratará como una nueva entidad.

Si MySet tiene una referencia a MyProperty y desea una copia de ella también, simplemente use un Include:

var originalEntity = Context.MySet.Include("MyProperty")
                            .AsNoTracking()
                            .FirstOrDefault(e => e.Id == 1);
 118
Author: Leo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-10 12:58:42

Aquí hay otra opción.

Lo prefiero en algunos casos porque no requiere que ejecute una consulta específicamente para obtener datos para ser clonados. Puede usar este método para crear clones de entidades que ya haya obtenido de la base de datos.

//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();

Este método copia los valores actuales de la fuente a una nueva fila que se ha agregado.

 21
Author: Jas Laferriere,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-15 00:05:07

Este es un método de extensión genérico que permite la clonación genérica.

Tienes que buscar System.Linq.Dynamic de 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;
    }

Lo único que tienes que implementar es el método GetKeyName. Esto podría ser cualquier cosa desde return typeof(TEntity).Name + "Id" hasta return the first guid property o devolver la primera propiedad marcada con DatabaseGenerated(DatabaseGeneratedOption.Identity)].

En mi caso ya marqué mis clases con [DataServiceKeyAttribute("EntityId")]

    private string GetKeyName<TEntity>() where TEntity : class
    {
        return ((DataServiceKeyAttribute)typeof(TEntity)
           .GetCustomAttributes(typeof(DataServiceKeyAttribute), true).First())
           .KeyNames.Single();
    }
 1
Author: Jürgen Steinblock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-27 07:01:35