当我尝试将实体附加到上下文时,我得到一个异常
具有相同密钥的对象 存在于ObjectStateManager中。该 ObjectStateManager无法跟踪 具有相同键的多个对象
这是预期的行为。
但我想知道ObjectStateManager是如何知道的?
之前我想自己检查一下答案 0 :(得分:73)
如果您使用的是DbContext API(您首先提到了ef-code),您只需使用:
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);
答案 1 :(得分:13)
这是一个从上下文中获取对象的扩展方法,而不必担心它是否已经附加:
public 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 });
答案 2 :(得分:3)
检查
entity.EntityState == System.Data.EntityState.Detached
之前
答案 3 :(得分:3)
请注意,如果在您的上下文中禁用了更改跟踪,则询问ObjectStateManager
或ChangeTracker
可能会返回该对象不在ObjectContext
中如果它实际上已经在那里了。因此,如果您尝试附加此类对象,则会引发异常。
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);
答案 4 :(得分:0)
您可以使用“Any”扩展方法查询dbContext:
bool alreadyInDB = dbContext.Entity.Where(a=>a.ID==myEntity.id).Any();
答案 5 :(得分:0)
如果您像我一样到达这里,是从EF Core延迟加载场景中进行的,在该场景中,当Entity附加到DbContext时,通过DbSet.Include()子句将导航属性填充到数据层中,然后该实体已分离并传递到业务层,请考虑将以下内容添加到您的DbContext.OnConfiguring(DbContextOptionsBuilder optionsBuilder)方法中:
optionsBuilder.ConfigureWarnings(warn => warn.Ignore(CoreEventId.LazyLoadOnDisposedContextWarning));
该错误将被忽略,并将返回最初包含()d的值。