C# 未能附加分离的实体(具有相同键的实体已在上下文中)

C# 未能附加分离的实体(具有相同键的实体已在上下文中),c#,entity-framework,C#,Entity Framework,我使用的是实体框架6,代码优先的方法。我将尝试用一段简单的代码来说明我的问题: public void ViewEntity(MyEntity Entity) // Want to read properties of my entity { using (var Db = new MyDbContext()) { var DummyList = Db.MyEntities.ToList(); // Iteration on this DbSet

我使用的是实体框架6,代码优先的方法。我将尝试用一段简单的代码来说明我的问题:

public void ViewEntity(MyEntity Entity) // Want to read properties of my entity
{
    using (var Db = new MyDbContext()) 
    {
        var DummyList = Db.MyEntities.ToList(); // Iteration on this DbSet
        Db.MyEntities.Attach(Entity); // Exception
    }
}
异常消息是:附加“MyProgram.MyEntity”类型的实体失败,因为相同类型的另一个实体已具有相同的主键值

从我在MSDN上看到的情况来看,这是一种预期的行为。但我想在最后一行首先检查是否有一个实体已经将相同的键附加到上下文中;如果是,请改用它,并且仅以其他方式将我的实体附加到上下文

但我没能找到一个办法。ObjectContext实例上有许多实用程序方法(例如GetObjectByKey)。我不能全部测试它们,因为它们最终都需要一个qualifiedEntitySetName,而我真正的imlpementation中没有,因为这个方法应该在一个抽象类上,并且应该适用于所有实体类型。调用Db.Entity(this)是没有用的,没有EntityKey具有EntitySetName

所有这些都很快变得复杂起来。用我的话说,我只想检查对象是否已经在“缓存”(上下文)中,使用它,否则使用我的对象并将其附加到这个上下文中


首先,我有一个与TreeNode.Tag分离的对象,我只想再次使用它,或者如果不可能的话;如果上下文中已有一个,请使用该上下文。也许我遗漏了EF6的一些关键概念,我只是从EF开始。

实体可以分为五个阶段:添加、不变、修改、删除、分离

public void ViewEntity(MyEntity entity) // Want to read properties of my entity
{
    using (var Db = new MyDbContext()) 
    {
       var DummyList = Db.MyEntities.ToList(); // Iteration on this DbSet
       // Set the Modified state of entity or you can write defensive code 
       // to check it before set the state.
       if (Db.Entry(entity).State == EntityState.Modified) {
          Db.Entry(entity).State = EntityState.Modified
       }

       // Attached it
       Db.MyEntities.Attach(Entity);

       Db.SaveChanges();
    }
}

由于EF不知道哪些属性与数据库中的属性不同,它将更新所有属性。

我找到了一个解决方案。正如我正确猜测的那样,ObjectContext.GetObjectByKey方法实现了我所需要的功能,但首先我需要构造qualifiedEntitySetName,并且我找到了一种实现方法。有点麻烦(使用反射、迭代MyDbContext的属性),但与我从所有这些中发现的令人头痛的问题相比,这是不一样的。以防万一,下面是一个补丁代码,它是我的解决方案:

public SdsAbstractObject GetAttachedToContext()
{
    var ObjContext = (SdsDbContext.Current as IObjectContextAdapter).ObjectContext;
    var ExistingItem = ObjContext.GetObjectByKey(GetEntityKey()) as SdsAbstractObject;    
    if (ExistingItem != null)
        return ExistingItem;
    else
    {
        DbSet.Attach(this);
        return this;
    }
} 

public EntityKey GetEntityKey()
{
    string DbSetName = "";
    foreach (var Prop in typeof(SdsDbContext).GetProperties())
    {
        if (Prop.PropertyType.IsGenericType
            && Prop.PropertyType.GenericTypeArguments[0] == ObjectContext.GetObjectType(GetType()))
            DbSetName = Prop.Name;
    }
    if (String.IsNullOrWhiteSpace(DbSetName))
        return null;
    else
        return new EntityKey("SdsDbContext." + DbSetName, "Id", Id);
}

这没用。当执行Db.Entry(entity).State行时,即使在“Attach”行之前,它也会立即给出相同的错误。但我找到了解决办法。不是很漂亮,但很管用。为了以防万一像我这样的新手需要它,我已经发布了我自己问题的答案。你可以在上面看看我的答案。