Существует хорошая статья здесь об объединении простого синтаксического анализатора с рекурсивным спуском с синтаксическим анализом по грамматике предшествования оператора. Если Вы недавно писали синтаксические анализаторы, это должно быть очень интересно и поучительно для чтения.
Вот то, что у меня получилось, и это очень хорошо работает:
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 (...)
за исключением того, что вы можете каждый раз использовать трюк с идентификатором, который я цитировал выше. В итоге вы получаете либо прикрепленный ранее объект, либо прикрепленный ваш собственный объект. Вызов CreateEntityKey
в контексте гарантирует, что он будет красивым и универсальным и будет работать даже с составными ключами без дальнейшего кодирования (потому что EF уже может сделать это за нас!).
Попробуйте этот метод расширения (это непроверено и нестандартно):
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.EntityKey
(из интерфейса IEntityWithKey
).
Использование ключа сущности объекта, который вы пытаетесь проверить:
var entry = context.ObjectStateManager.GetObjectStateEntry("EntityKey");
if (entry.State == EntityState.Detached)
{
// Do Something
}
Доброта,
Дэн