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