Можно ли проверить, если объект уже присоединен к контексту данных в 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 "объект". Это не удается, потому что я ранее прикрепил этот фиктивный объект пользователя. Как я могу это проверить?

502   5  

5 ответов:

вот что я в конечном итоге, который работает очень хорошо:

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 уже может сделай это для нас!).

более простой подход:

 bool isDetached = context.Entry(user).State == EntityState.Detached;
 if (isDetached)
     context.Users.Attach(user);

попробуйте этот метод расширения (это непроверенный и вне манжеты):

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).

используя ключ сущности объекта, который вы пытаетесь проверить:

var entry = context.ObjectStateManager.GetObjectStateEntry("EntityKey");
if (entry.State == EntityState.Detached)
{
  // Do Something
}

доброжелательность,

Дэн

это не дает прямого ответа на вопрос OPs, но вот как я решил свой.

это для тех, кто использует DbContext вместо ObjectContext.

    public TEntity Retrieve(object primaryKey)
    {
        return DbSet.Find(primaryKey);
    }

DbSet.Найти Метод:

находит объект с заданными значениями первичного ключа. Если сущность с заданные значения первичного ключа существуют в контексте, то это тут же вернулся не сделав запрос в магазин. Иначе, запрос в магазин для сущность с заданным первичным объектом Ключевые значения и эта сущность, если она найдена, присоединяется к контексту и возвращенный. Если ни одна сущность не найдена в контексте или хранилище, то null возвращенный.

в принципе, он возвращает вложенный объект данного primaryKey поэтому вам просто нужно применить изменения к возвращаемому объекту, чтобы сохранить правильный экземпляр.

Comments

    Ничего не найдено.