Возможно ли проверить, что объект уже привязан к контексту данных в Entity Framework?
Я получаю следующую ошибку при попытке присоединить объект, который уже прикреплен к данному контексту через context.AttachTo(...)
:
Объект с тем же ключом уже существует в ObjectStateManager. ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом.
Есть ли способ достичь чего-то по строкам:
context.IsAttachedTo(...)
Ура!
Edit:
Метод расширения, обозначенный Джейсоном, близок, но он не работает для моей ситуации.
Я пытаюсь выполнить некоторую работу, используя метод, описанный в ответе на другой вопрос:
Как удалить одну или несколько строк из моей таблицы с помощью Linq to Entities * без * получения строк вначале?
Мой код выглядит примерно так:
var user = new User() { Id = 1 };
context.AttachTo("Users", user);
comment.User = user;
context.SaveChanges();
Это отлично работает, за исключением случаев, когда я делаю что-то еще для этого пользователя, где я использую тот же метод и пытаюсь прикрепить фиктивный объект User
. Это не удается, потому что я ранее прикреплял этот фиктивный пользовательский объект. Как я могу проверить это?
Ответы
Ответ 1
Вот что я закончил, что очень хорошо работает:
public static void AttachToOrGet<T>(this ObjectContext context, string entitySetName, ref T entity)
where T : IEntityWithKey
{
ObjectStateEntry entry;
// Track whether we need to perform an attach
bool attach = false;
if (
context.ObjectStateManager.TryGetObjectStateEntry
(
context.CreateEntityKey(entitySetName, entity),
out entry
)
)
{
// Re-attach if necessary
attach = entry.State == EntityState.Detached;
// Get the discovered entity to the ref
entity = (T)entry.Entity;
}
else
{
// Attach for the first time
attach = true;
}
if (attach)
context.AttachTo(entitySetName, entity);
}
Вы можете вызвать его следующим образом:
User user = new User() { Id = 1 };
II.AttachToOrGet<Users>("Users", ref user);
Это работает очень хорошо, потому что это точно так же, как context.AttachTo(...)
, за исключением того, что вы каждый раз можете использовать трюк ID, который я цитировал выше. Вы получаете либо объект, который был ранее прикреплен, либо ваш собственный объект. Вызов CreateEntityKey
в контексте делает его приятным и универсальным и будет работать даже с составными клавишами без дальнейшего кодирования (потому что EF уже может это сделать для нас!).
Ответ 2
Более простой подход:
bool isDetached = context.Entry(user).State == EntityState.Detached;
if (isDetached)
context.Users.Attach(user);
Ответ 3
Попробуйте этот метод расширения (это непроверено и отключено):
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;
}
Учитывая ситуацию, описанную в вашем редактировании, вам может потребоваться использовать следующую перегрузку, которая принимает EntityKey
вместо объекта:
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;
}
Чтобы построить EntityKey
в вашей ситуации, используйте в качестве ориентира следующее:
EntityKey key = new EntityKey("MyEntities.User", "Id", 1);
Вы можете получить EntityKey
из существующего экземпляра User
с помощью свойства User.EntityKey
(из интерфейса IEntityWithKey
).
Ответ 4
Использование ключа сущности объекта, который вы пытаетесь проверить:
var entry = context.ObjectStateManager.GetObjectStateEntry("EntityKey");
if (entry.State == EntityState.Detached)
{
// Do Something
}
Доброта,
Dan
Ответ 5
Это напрямую не отвечает на вопрос OP, но именно так я и решил.
Это для тех, кто использует DbContext
вместо ObjectContext
.
public TEntity Retrieve(object primaryKey)
{
return DbSet.Find(primaryKey);
}
Метод DbSet.Find:
Находит объект с указанными значениями первичного ключа. Если объект с значения данного первичного ключа существуют в контексте, то это немедленно возвращается без запроса в магазин. В противном случае, в хранилище запрашивается запрос для лица с данным первичным ключевые значения, и этот объект, если найден, присоединен к контексту и вернулся. Если ни один объект не найден в контексте или в хранилище, то null возвращается.
В принципе, он возвращает прикрепленный объект данного primaryKey
, поэтому вам просто нужно применить изменения на возвращаемом объекте, чтобы сохранить правильный экземпляр.