Radu Negrila
Radu Negrila

Reputation: 667

EntityFramework Code First - Check if Entity is attached

I am trying to update an entity with a FK relationship in EntityFramework 4.3 Code First. I try to attach to the related entites by calling: Entry(item).State = EntityState.Unchanged

I get the following exception: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.

I do not update these items nor have an id property for them on my main entity. Is it possible to know which entities are attached or not ?

Thanks in advance, Radu

Upvotes: 51

Views: 42702

Answers (4)

VictorV
VictorV

Reputation: 1059

You can use this method:

    /// <summary>
    /// Determines whether the specified entity key is attached.
    /// </summary>
    /// <param name="context">The context.</param>
    /// <param name="key">The key.</param>
    /// <returns>
    ///   <c>true</c> if the specified context is attached; otherwise, <c>false</c>.
    /// </returns>
    internal static bool IsAttached(this ObjectContext context, 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;
    }

For example:

     if (!_objectContext.IsAttached(entity.EntityKey))
        {
            _objectContext.Attach(entity);
        }

Upvotes: 11

Beingnin
Beingnin

Reputation: 2422

I use this extension method since I needed to check tracking based on values, not based on instance

internal static class DBExtensions
    {
        internal static bool IsAttached<TEntity>(this DbSet<TEntity> dbSet, Func<TEntity, bool> condition) where TEntity : class
        {
            return dbSet.Local.Any(condition);
        }
    }

Usage:

 if (!context.Items.IsAttached(y => y.ItemId == item.ItemId))
    {
        context.Items.Attach(item);
    }

Upvotes: 0

KramFfud
KramFfud

Reputation: 229

If you have arrived here from an EF Core Lazy Loading scenario in which Navigation properties were filled in a data layer via DbSet<>.Include() clause(s) while the Entity was attached to a DbContext and then that Entity was detached and passed up to a business layer, consider adding something like this to your DbContext.OnConfiguring(DbContextOptionsBuilder optionsBuilder) method: optionsBuilder.ConfigureWarnings(warn => warn.Ignore(CoreEventId.LazyLoadOnDisposedContextWarning)); The error will be ignored and the values that were originally Include()d will be returned.

Upvotes: 1

Tri Q Tran
Tri Q Tran

Reputation: 5690

You can find the answer here.

public bool Exists<T>(T entity) where T : class
{
    return this.Set<T>().Local.Any(e => e == entity);
}

Place that code into your context or you can turn it into an extension like so.

public static bool Exists<TContext, TEntity>(this TContext context, TEntity entity)
    where TContext : DbContext
    where TEntity : class
{
    return context.Set<TEntity>().Local.Any(e => e == entity);
}

Upvotes: 94

Related Questions