Reputation: 667
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
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
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
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
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