Каков наиболее разумный способ узнать, присоединен ли объект к dbContext или нет? - PullRequest
54 голосов
/ 17 мая 2011

когда я пытаюсь присоединить объект к контексту, я получаю исключение

Объект с таким же ключом уже существует в ObjectStateManager.ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом

Это ожидаемое поведение.

Но я хотел бы знать, как ObjectStateManager это знает?Я хотел бы сделать эту проверку самостоятельно до

Ответы [ 5 ]

74 голосов
/ 18 мая 2011

Если вы используете DbContext API (вы упомянули ef-code-first), вы можете просто использовать:

context.YourEntities.Local.Any(e => e.Id == id);

или более сложный

context.ChangeTracker.Entries<YourEntity>().Any(e => e.Entity.Id == id);

В случае ObjectContext API выможно использовать:

context.ObjectStateManager.GetObjectStateEntries(~EntityState.Detached)
                          .Where(e => !e.IsRelationship)
                          .Select(e => e.Entity)
                          .OfType<YourEntity>()
                          .Any(x => x.Id == id);
13 голосов
/ 17 июня 2013

Вот метод расширения для получения объекта из контекста, не беспокоясь о том, подключен ли он уже:

public static T GetLocalOrAttach<T>(this DbSet<T> collection, Func<T, bool> searchLocalQuery, Func<T> getAttachItem) where T : class
{
    T localEntity = collection.Local.FirstOrDefault(searchLocalQuery);

    if (localEntity == null)
    {
        localEntity = getAttachItem();
        collection.Attach(localEntity);
    }

    return localEntity;
}

Просто вызовите:

UserProfile user = dbContext.UserProfiles.GetLocalOrAttach<UserProfile>(u => u.UserId == userId, () => new UserProfile { UserId = userId });
4 голосов
/ 17 мая 2011

проверьте

entity.EntityState == System.Data.EntityState.Detached

перед прикреплением

3 голосов
/ 07 апреля 2014

Обратите внимание, что если отслеживание изменений отключено в вашем контексте, запрос ObjectStateManager или ChangeTracker может возвратить, что объект не находится в ObjectContext, даже если он на самом деле уже находится втам.Поэтому, если вы попытаетесь прикрепить такой объект, это вызовет исключение.

context.Set<T>.Local.Any(e => e.Id == id);

работает событие, если отслеживание изменений отключено.

, если вы не знаете тип объекта, тамЭто другой подход, либо вы определяете метод с использованием отражения, либо другие методы, подобные этому int GetIdOf(object entity){...}

Или вы определяете интерфейс, используемый вашими классами, например

public interface IMyEntity
{
    int Id{get;set;}
}

, и используете его таким образом:

context.Set(e.GetType()).Local.Cast<IMyEntity>().Any(e => e.Id == id);
0 голосов
/ 18 мая 2011

Вы можете запросить dbContext с помощью метода расширения «Any»:

bool alreadyInDB = dbContext.Entity.Where(a=>a.ID==myEntity.id).Any();
...