program story

Entity Framework 5 엔터티의 전체 복사 / 복제

inputbox 2020. 11. 4. 07:56
반응형

Entity Framework 5 엔터티의 전체 복사 / 복제


Entity Framework 5 ( DBContext)를 사용하고 있으며 엔터티를 딥 복사 (즉, 엔터티 및 모든 관련 개체 복사) 한 다음 새 엔터티를 데이터베이스에 저장하는 가장 좋은 방법을 찾으려고합니다. 어떻게 할 수 있습니까? 다음과 같은 확장 방법을 사용해 보았지만에 CloneHelper적용되는지 확실하지 않습니다 DBContext.


엔티티를 복제하는 저렴한 쉬운 방법은 다음과 같이하는 것입니다.

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.Dynamicnuget에서.

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

하위 항목이 지연로드 될 때 깊은 복제에 여러 단계가 포함되는 Entity Framework Core에서 동일한 문제가 발생했습니다. 전체 구조를 복제하는 한 가지 방법은 다음과 같습니다.

   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 generic functions to eager load everything and/or reset values for all keys, but this should make all the steps much clear and customizable (e.g. all for some children to not be cloned at all, by skipping their Include).

참고URL : https://stackoverflow.com/questions/15308747/entity-framework-5-deep-copy-clone-of-an-entity

반응형