Używam Entity Framework 5 (DBContext
) i staram się znaleźć najlepszy sposób, aby skopiować kopię obiektu (tj. Skopiować obiekt i wszystkie powiązane obiekty), a następnie zapisać nowe jednostki w bazie danych. Jak mogę to zrobić? Przyjrzałem się przy użyciu metod rozszerzenia, takich jak CloneHelper
, ale nie jestem pewien, czy ma to zastosowanie do DBContext
.Entity Framework 5 deep copy/clone podmiotu
Odpowiedz
Jeden tani łatwy sposób klonowania podmiot jest zrobić coś takiego:
var originalEntity = Context.MySet.AsNoTracking()
.FirstOrDefault(e => e.Id == 1);
Context.MySet.Add(originalEntity);
Context.SaveChanges();
trick Oto AsNoTracking() - podczas ładowania podmiotu takiego, context nie wiem o to i kiedy zadzwonisz SaveChanges, potraktuje to jak nowy byt.
Jeśli MySet
ma odniesienie do MyProperty
i chcesz kopię tego też wystarczy użyć Include
:
var originalEntity = Context.MySet.Include("MyProperty")
.AsNoTracking()
.FirstOrDefault(e => e.Id == 1);
Ta sztuczka tylko zapewniła mi sporo czasu :-). Ale w mojej konfiguracji DbContext wystąpił wyjątek dotyczący braku możliwości automatycznego dodania encji. Musiałem przejść przez ObjectContext tak jak to DirectCast (DbContext, IObjectContextAdapter) .ObjectContext.AddObject (entitySetName, entity) ' – Patrick
Mam projekcję z kontekstu ef takiego jak ten' dbContext, Select (x => {a = x, ab = x.MyCollection.Where (g => g.Id> 2)}) ToList() 'Jeśli dodaję' AsNoTracking() 'Istnieje utrata danych z zapytania. – Eldho
To zadziałało dla mnie, używając EF Core. Jednak musiałem ustawić moje podstawowe klucze na obiekcie macierzystym i zagnieżdżonych na Guid.Empty, aby zapobiec EF próbując wstawić zduplikowane wiersze w bazie danych. Jeśli użyjesz klawiszy całkowitych, podejrzewam, że ustawienie ich na 0 miałoby taki sam efekt. – agileMike
Oto kolejna opcja.
Preferuję to w niektórych przypadkach, ponieważ nie wymaga to uruchomienia zapytania specjalnie w celu pobrania danych do sklonowania. Możesz użyć tej metody do tworzenia klonów 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.
Działa to świetnie, jeśli chcesz, aby klon był wstawiany razem z aktualizacjami oryginału w jednym SaveChanges – Dacker
'SetValues' nie działa, jeśli nowy obiekt nie jest dołączony do kontekst. Zgłasza wyjątek 'InvalidOperationException'. Jeśli chcesz tylko sklonować obiekt w stanie odłączonym, możesz dodać obiekt do kontekstu, ustawić jego bieżące wartości, a następnie odłączyć je. – Suncat2000
Jest to ogólna metoda rozszerzenia, która umożliwia generyczne 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;
}
Jedyne, co trzeba samemu zaimplementować, to metoda GetKeyName. Może to być cokolwiek od do return the first guid property
lub zwrócić pierwszą właściwość oznaczoną DatabaseGenerated(DatabaseGeneratedOption.Identity)]
.
W moim przypadku już zaznaczono moje zajęcia z [DataServiceKeyAttribute("EntityId")]
private string GetKeyName<TEntity>() where TEntity : class
{
return ((DataServiceKeyAttribute)typeof(TEntity)
.GetCustomAttributes(typeof(DataServiceKeyAttribute), true).First())
.KeyNames.Single();
}
Próbowałem Deep klon/powielać obiekty podmiot korzystający odbicie opisanej w poniższym [LINK] (http://code.msdn.microsoft. com/CSEFDeepCloneObject-12a5cb95), ale jak rozumiem, typy pochodne EntityObject nie są obsługiwane przez interfejs API DbContext – kypk