Entity Framework 5 глубокое копирование / клонирование объекта



Я использую Entity Framework 5 (DBContext) и я пытаюсь найти лучший способ глубокого копирования сущности (т. е. скопировать сущность и все связанные объекты), а затем сохранить новые сущности в базе данных. Как я могу это сделать? Я изучил использование методов расширения, таких как CloneHelper но я не уверен, если это относится к DBContext.

575   3  

3 ответов:

один дешевый простой способ клонирования сущность-это что-то вроде этого:

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

хитрость тут AsNoTracking() - когда вы загружаете такой объект, ваш контекст не знает об этом, и когда вы вызываете SaveChanges, он будет рассматривать его как новый объект.

если MySet имеет ссылку на MyProperty и вы хотите его копию тоже, просто используйте Include:

var originalEntity = Context.MySet.Include("MyProperty")
                            .AsNoTracking()
                            .FirstOrDefault(e => e.Id == 1);

вот еще один вариант.

Я предпочитаю его в некоторых случаях, потому что он не требует выполнения запроса специально для получения данных для клонирования. Этот метод можно использовать для создания клонов сущностей, уже полученных из базы данных.

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

этот метод копирует текущие значения из источника в новую добавленную строку.

это универсальный метод расширения, который позволяет обычным клонированием.

вы должны принести System.Linq.Dynamic от 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;
    }

единственное, что вам нужно реализовать самостоятельно, это метод GetKeyName. Это может быть что угодно от return typeof(TEntity).Name + "Id" до return the first guid property или вернуть первое свойство, помеченное DatabaseGenerated(DatabaseGeneratedOption.Identity)].

в моем случае я уже отметил свои классы с [DataServiceKeyAttribute("EntityId")]

    private string GetKeyName<TEntity>() where TEntity : class
    {
        return ((DataServiceKeyAttribute)typeof(TEntity)
           .GetCustomAttributes(typeof(DataServiceKeyAttribute), true).First())
           .KeyNames.Single();
    }

Comments

    Ничего не найдено.