каков наиболее разумный способ узнать, прикреплена ли сущность к dbContext или нет?
когда я пытаюсь присоединить сущность к контексту, я получаю исключение
объект с тем же ключом уже существует в ObjectStateManager. Этот ObjectStateManager не может отследить несколько объектов с одним и тем же ключом
это ожидаемое поведение.
но я хотел бы знать, как ObjectStateManager это знает? Я хотел бы сделать эту проверку самостоятельно, прежде чем
5 ответов:
Если вы используете 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);
вот метод расширения для получения объекта из контекста, не беспокоясь о том, что уже добавленные:
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 });
обратите внимание, что если отслеживание изменений отключается в вашем контексте, задавая
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);