Otrzymuję następujący błąd podczas próby dołączenia obiektu, który jest już dołączony do danego kontekstu za pośrednictwem context.AttachTo(...)
:
Obiekt z tym samym kluczem już istnieje w ObjectStateManager. ObjectStateManager nie może śledzić wielu obiektów za pomocą tego samego klucza.
Czy istnieje sposób na osiągnięcie czegoś w rodzaju:
context.IsAttachedTo(...)
Twoje zdrowie!
Edytować:
Metoda rozszerzenia, którą przedstawił Jason, jest bliska, ale nie działa w mojej sytuacji.
Próbuję trochę popracować metodą opisaną w odpowiedzi na inne pytanie:
Mój kod wygląda trochę tak:
var user = new User() { Id = 1 };
context.AttachTo("Users", user);
comment.User = user;
context.SaveChanges();
Działa to dobrze, z wyjątkiem sytuacji, gdy robię coś innego dla tego użytkownika, gdzie używam tej samej metody i próbuję dołączyć User
obiekt zastępczy . Nie udaje się to, ponieważ wcześniej dołączyłem ten fikcyjny obiekt użytkownika. Jak mogę to sprawdzić?
źródło
(T)entry.Entity
czasami zwraca wartość null?T
już jestIEntityWithKey
, czy nie możesz po prostu użyć jegoentity.EntityKey
właściwości, zamiast ją rekonstruować lub musisz zgadywać / podawaćEntitySetName
?Prostsze podejście to:
bool isDetached = context.Entry(user).State == EntityState.Detached; if (isDetached) context.Users.Attach(user);
źródło
.Include()
właściwości nawigacji ed są również próbowane, gdy wywołujesz.Attach
lub ustawia jeEntityState
naEntityState.Unchanged
- i będą one sprzeczne, jeśli którakolwiek z jednostek odwołuje się do ten sam podmiot. Nie wymyśliłem, jak dołączyć tylko element bazowy, więc musiałem nieco przeprojektować projekt, aby użyć oddzielnych kontekstów dla każdej „transakcji biznesowej”, tak jak została zaprojektowana. Zanotuję to dla przyszłych projektów.Wypróbuj tę metodę przedłużania (nie została przetestowana i jest poza mankietem):
public static bool IsAttachedTo(this ObjectContext context, object entity) { if(entity == null) { throw new ArgumentNullException("entity"); } ObjectStateEntry entry; if(context.ObjectStateManager.TryGetObjectStateEntry(entity, out entry)) { return (entry.State != EntityState.Detached); } return false; }
Biorąc pod uwagę sytuację, którą opisujesz w swojej edycji, może być konieczne użycie następującego przeciążenia, które akceptuje obiekt
EntityKey
zamiast:public static bool IsAttachedTo(this ObjectContext, EntityKey key) { if(key == null) { throw new ArgumentNullException("key"); } ObjectStateEntry entry; if(context.ObjectStateManager.TryGetObjectStateEntry(key, out entry)) { return (entry.State != EntityState.Detached); } return false; }
Aby zbudować
EntityKey
w swojej sytuacji, użyj następujących wskazówek:EntityKey key = new EntityKey("MyEntities.User", "Id", 1);
Możesz pobrać
EntityKey
z istniejącej instancji programuUser
przy użyciu właściwościUser.EntityKey
(z interfejsuIEntityWithKey
).źródło
TryGetObjectStateEntry
które akceptujeEntityKey
zamiastobject
. Odpowiednio zredagowałem. Daj mi znać, jeśli to nie pomoże, a wrócimy do deski kreślarskiej.Używając klucza encji obiektu, który próbujesz sprawdzić:
var entry = context.ObjectStateManager.GetObjectStateEntry("EntityKey"); if (entry.State == EntityState.Detached) { // Do Something }
Życzliwość,
Dan
źródło
To nie odpowiada bezpośrednio na pytanie PO, ale tak rozwiązałem swoje.
To jest dla tych, którzy używają
DbContext
zamiastObjectContext
.public TEntity Retrieve(object primaryKey) { return DbSet.Find(primaryKey); }
Metoda DbSet.Find :
Zasadniczo zwraca dołączony obiekt danego podanego,
primaryKey
więc wystarczy zastosować zmiany w zwróconym obiekcie, aby zachować właściwą instancję.źródło