Ostatnio pracowałem z Entity Framework 4 i jestem nieco zdezorientowany, kiedy używać ObjectSet.Attach i ObjectSet.AddObject .
Z mojego zrozumienia:
- Użyj opcji „Dołącz”, gdy jednostka już istnieje w systemie
- Użyj „AddObject” podczas tworzenia zupełnie nowej jednostki
Tak więc, jeśli tworzę nową osobę , robię to.
var ctx = new MyEntities();
var newPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.AddObject(newPerson);
ctx.SaveChanges();
Jeśli modyfikuję istniejącą osobę , robię to:
var ctx = new MyEntities();
var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
existingPerson.Name = "Joe Briggs";
ctx.SaveChanges();
Pamiętaj, że to bardzo prosty przykład. W rzeczywistości używam Pure POCO (bez generowania kodu), wzorca repozytorium (nie zajmuję się ctx.Persons) i jednostki pracy (nie zajmuję się ctx.SaveChanges). Ale „pod kołdrą”, powyższe dzieje się w mojej realizacji.
Teraz moje pytanie - nie znalazłem jeszcze scenariusza, w którym musiałem użyć Attach .
Czego tu brakuje? Kiedy musimy używać Attach?
EDYTOWAĆ
Aby wyjaśnić, szukam przykładów, kiedy używać Attach zamiast AddObject (lub odwrotnie).
EDYCJA 2
Poniższa odpowiedź jest poprawna (którą zaakceptowałem), ale pomyślałem, że dodam kolejny przykład, w którym Attach byłby przydatny.
W moim powyższym przykładzie dotyczącym modyfikowania istniejącej osoby faktycznie wykonywane są dwa zapytania.
Jeden do pobierania osoby (.SingleOrDefault), a drugi do wykonywania AKTUALIZACJI (.SaveChanges).
Jeśli (z jakiegoś powodu) już wiedziałem, że „Joe Bloggs” istnieje w systemie, po co dodatkowe zapytanie, aby go znaleźć? Mógłbym to zrobić:
var ctx = new MyEntities();
var existingPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.Attach(existingPerson);
ctx.SaveChanges();
Spowoduje to wykonanie tylko instrukcji UPDATE.
źródło
Odpowiedzi:
ObjectContext.AddObject i ObjectSet.AddObject :
Metoda AddObject służy do dodawania nowo utworzonych obiektów, które nie istnieją w bazie danych. Encja otrzyma automatycznie wygenerowany tymczasowy EntityKey, a jej EntityState zostanie ustawiony na Dodano . Po wywołaniu SaveChanges będzie jasne dla EF, że ta jednostka musi zostać wstawiona do bazy danych.
ObjectContext.Attach i ObjectSet.Attach :
Z drugiej strony, Attach jest używany dla jednostek, które już istnieją w bazie danych. Zamiast ustawiać EntityState na Added, Attach skutkuje niezmienionym EntityState, co oznacza, że nie zmienił się od czasu dołączenia do kontekstu. Zakłada się, że dołączane obiekty istnieją w bazie danych. Jeśli zmodyfikujesz obiekty po ich dołączeniu, po wywołaniu SaveChanges wartość EntityKey zostanie użyta do zaktualizowania (lub usunięcia) odpowiedniego wiersza poprzez znalezienie pasującego identyfikatora w tabeli db.
Ponadto za pomocą metody Attach można zdefiniować relacje między jednostkami, które już istnieją w ObjectContext, ale mająnie został podłączony automatycznie. Zasadniczo głównym celem Attach jest połączenie jednostek, które są już dołączone do ObjectContext i nie sąnowe, więc nie można używać Attach do dołączania jednostek, których EntityState jest dodana. W takim przypadku musisz użyć Add () .
Na przykład załóżmy, że Twoja encja Person ma właściwość nawigacji o nazwie Adresy, która jest zbioremencji Adres . Powiedzmy, że przeczytałeś oba obiekty z kontekstu, ale nie są one ze sobą powiązane i chcesz, aby tak było:
var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" }; var myAddress = ctx.Addresses.First(a => a.PersonID != existingPerson.PersonID); existingPerson.Addresses.Attach(myAddress); // OR: myAddress.PersonReference.Attach(existingPerson) ctx.SaveChanges();
źródło
To jest późna odpowiedź, ale może pomóc innym, którzy ją znajdą.
Zasadniczo „odłączony” obiekt może się zdarzyć, gdy manipulujesz bytem poza zakresem „używania”.
Employee e = null; using (var ctx = new MyModelContainer()) { e = ctx.Employees.SingleOrDefault(emp => emp .....); } using (var ctx2 = new MyModelContainer()) { e; // This entity instance is disconnected from ctx2 }
Jeśli wprowadzisz inny zakres „używający”, zmienna „e” zostanie odłączona, ponieważ należy do poprzedniego zakresu „używającego”, a ponieważ poprzedni zakres „używający” zostanie zniszczony, wówczas „e” zostanie odłączony.
Tak to rozumiem.
źródło
To jest cytat z Programming Entity Framework: DbContext
private static void TestDeleteDestination() { Destination canyon; using (var context = new BreakAwayContext()) { canyon = (from d in context.Destinations where d.Name == "Grand Canyon" select d).Single(); } DeleteDestination(canyon); } private static void DeleteDestination(Destination destination) { using (var context = new BreakAwayContext()) { context.Destinations.Attach(destination); context.Destinations.Remove(destination); context.SaveChanges(); } }
źródło
A co powiesz na odwoływanie się tylko do klucza podstawowego zamiast dołączania?
to znaczy:
var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" }; var myAddress = ctx.Addresses.First(a => a.PersonID != existingPerson.PersonID); existingPerson.AddressId = myAddress.Id // not -> existingPerson.Addresses.Attach(myAddress); // OR: myAddress.Person.Id = existingPerson.Id // not -> myAddress.PersonReference.Attach(existingPerson); ctx.SaveChanges();
źródło