当我尝试将实体附加到上下文时,我收到了一个异常。
具有相同键的对象已经存在于ObjectStateManager中。 ObjectStateManager无法跟踪具有相同键的多个对象。
这是预期行为。
但是我想知道ObjectStateManager是如何知道的?我想在此之前自己进行此检查。
当我尝试将实体附加到上下文时,我收到了一个异常。
具有相同键的对象已经存在于ObjectStateManager中。 ObjectStateManager无法跟踪具有相同键的多个对象。
这是预期行为。
但是我想知道ObjectStateManager是如何知道的?我想在此之前自己进行此检查。
如果你正在使用 DbContext API(你提到了 ef-code-first),你可以简单地使用以下代码:
context.YourEntities.Local.Any(e => e.Id == id);
或更复杂
context.ChangeTracker.Entries<YourEntity>().Any(e => e.Entity.Id == id);
如果使用ObjectContext API,您可以使用以下方法:
context.ObjectStateManager.GetObjectStateEntries(~EntityState.Detached)
.Where(e => !e.IsRelationship)
.Select(e => e.Entity)
.OfType<YourEntity>()
.Any(x => x.Id == id);
context.Set(type).Local.Any(...)
- Ladislav MrnkaAny(e => e.Equals(yourEntity))
。 - Ladislav Mrnka((IObjectContextAdapter)context).ObjectContext.ObjectStateManager.GetObjectStateEntry(entity).EntityKey
获取。 - achekhpublic static T GetLocalOrAttach<T>(this DbSet<T> collection, Func<T, bool> searchLocalQuery, Func<T> getAttachItem) where T : class
{
T localEntity = collection.Local.FirstOrDefault(searchLocalQuery);
if (localEntity == null)
{
localEntity = getAttachItem();
collection.Attach(localEntity);
}
return localEntity;
}
只需要调用:
UserProfile user = dbContext.UserProfiles.GetLocalOrAttach<UserProfile>(u => u.UserId == userId, () => new UserProfile { UserId = userId });
检查
entity.EntityState == System.Data.EntityState.Detached
在附加之前
context.Set<T>().Local.Any(e => e.Id == id);
即使关闭更改跟踪,也可以工作。
如果您不知道对象的类型,则有不同的方法,可以使用反射或其他类似于此代码的技术定义一个方法:
int GetIdOf(object entity){...}
或者您可以定义一个由您的类使用的接口:
public interface IMyEntity
{
int Id{get;set;}
}
并且这样使用它:
context.Set(e.GetType()).Local.Cast<IMyEntity>().Any(e => e.Id == id);
您可以使用“Any”扩展方法查询dbContext:
bool alreadyInDB = dbContext.Entity.Where(a=>a.ID==myEntity.id).Any();
optionsBuilder.ConfigureWarnings(warn => warn.Ignore(CoreEventId.LazyLoadOnDisposedContextWarning));
var exists = (dbContext.entities.Where(e=>e.ID == myEntity.ID).Count() > 0);
或者类似的操作。 - Lazarus