Entity Framework 5 deep copy/clone of an entity

Używam encji Framework 5 (DBContext) i staram się znaleźć najlepszy sposób, aby głęboko skopiować encję (tj. skopiować encję i wszystkie powiązane obiekty), a następnie zapisać nowe encje w bazie danych. Jak mogę to zrobić? Przyjrzałem się metodom rozszerzenia, takim jak CloneHelper, ale nie jestem pewien, czy dotyczy to DBContext.

Author: Chris, 2013-03-09

3 answers

Jednym z tanich, łatwych sposobów klonowania bytu jest zrobienie czegoś takiego:

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

Sztuczka polega na tym, że AsNoTracking () - kiedy załadujesz encję w ten sposób, twój kontekst o niej nie wie i kiedy wywołasz SaveChanges, będzie traktował ją jak nową encję.

Jeśli MySet ma odniesienie do MyProperty i chcesz mieć jego kopię, po prostu użyj 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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-10 12:58:42

Oto inna opcja.

Wolę go w niektórych przypadkach, ponieważ nie wymaga uruchamiania zapytania specjalnie w celu uzyskania danych do klonowania. Możesz użyć tej metody, aby utworzyć klony jednostek, które już uzyskałeś z bazy danych.

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

Ta metoda kopiuje bieżące wartości ze źródła do nowego wiersza, który został dodany.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-15 00:05:07

Jest to ogólna metoda rozszerzenia, która umożliwia ogólne klonowanie.

Musisz pobrać System.Linq.Dynamic z 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;
    }

Jedyną rzeczą, którą musisz zaimplementować, jest metoda GetKeyName. Może to być cokolwiek od return typeof(TEntity).Name + "Id" do return the first guid property lub zwróć pierwszą właściwość oznaczoną DatabaseGenerated(DatabaseGeneratedOption.Identity)].

W moim przypadku już oznaczyć moje zajęcia [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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-27 07:01:35