找出实体是否附加到dbContext的最合理方法是什么?

时间:2011-05-17 15:39:58

标签: c# entity-framework-4 ef-code-first

当我尝试将实体附加到上下文时,我得到一个异常

  

具有相同密钥的对象   存在于ObjectStateManager中。该   ObjectStateManager无法跟踪   具有相同键的多个对象

这是预期的行为。

但我想知道ObjectStateManager是如何知道的?

之前我想自己检查一下

6 个答案:

答案 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)

请注意,如果在您的上下文中禁用了更改跟踪,则询问ObjectStateManagerChangeTracker可能会返回该对象不在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的值。