【问题标题】:EF4 adding multiple entities (An object with the same key already exists in the ObjectStateManager)EF4 添加多个实体(ObjectStateManager 中已存在具有相同键的对象)
【发布时间】:2010-11-17 04:26:27
【问题描述】:

我有一个对象,上面有很多属性。一堆这些大对象将被插入到数据库中,但它们只有一个属性发生变化。将要更改的属性不是主键。第一次 SaveChanges 成功,但随后的失败并显示“ObjectStateManager 中已存在具有相同键的对象.....”。这是代码中的流程:

    //create the entity and set the properties that don't change
    TheLargeObject obj = new TheLargeObject();
    obj.Prop1 = 
    obj.Prop2 = 
    ...
    obj.Prop20 = 

    //create a list of values that differ between each entity
    List<int> validIds = new List<int>();

    private static void SaveToDatabase(TheLargeObject obj, List<int> validIds)
    {

        foreach (int id in validIds)
        {
            //this is the only property that changes
            obj.KeyId = id;

            //make a copy - do we really need this?
            TheLargeObject newobj = new TheLargeObject();
            newobj = obj;

            using(Entities objContext = new Entities())
            {
                objContext.TheLargeObjects.AddObject(newobj); //ERROR: An object with the same key already exists in the ObjectStateManager.  
                objContext.SaveChanges();
            }
        }
    }

我刚刚开始使用 EF4,所以我可能会以错误的方式处理这个问题。 谢谢

【问题讨论】:

  • 你为什么不接受答案?

标签: entity-framework-4


【解决方案1】:

我不确定你想在这里做什么。主要是这句话让我感到困惑:

这些大对象的一堆将被插入到数据库中,但它们只有一个属性发生变化。

对象(即插入)如何改变?如果是新的,有什么要改变的?

模型中的所有实体都有一个EntityKey,它通常是数据库端的主键。

我认为你正在做的是.AddObject,而你应该做的是.Attach

插入新对象的方法如下:

var newFoo = new Foo();
ctx.Foos.AddObject(newFoo);
newFoo.SaveChanges();

更新现有对象的方法如下:

var existingFoo = ctx.Foos.SingleOrDefault(x => x.Id == 1); // or however you want to get it
existingFoo.Name = "Changed foo";
newFoo.SaveChanges();

或者如果你有一个分离的实体:

var existingFoo = new Foo();
existingFoo.Name = "Foo name";
ctx.Foos.Attach(existingFoo);
ctx.SaveChanges();

所以,我认为在您的示例中,您的代码应该是:

objContext.TheLargeObjects.Attach(newObject);
objContext.SaveChanges();

简而言之,如果您确定的实体已经存在于数据库中,并且您手动构建了该实体,请使用.Attach。如果您有一个全新的对象,请使用.AddObject

但是,为了安全起见 - 您可以再次获取对象,进行所需的更改,然后执行.SaveChanges()

.Attach 通常用于无状态场景,例如网站,在请求之间没有将对象保存在图中,因此要进行更改我们需要 .Attach,或者在进行更改之前再次检索对象。

希望这可以为您解决问题。

【讨论】:

  • 感谢您对混乱的回复和道歉。这将是一个新对象,所以我想要一个插入而不是更新。所以 .Attach 在我的情况下不起作用,因为实体不会在数据库中。创建对象非常耗时(因为属性集很大),因此我想要一种方法来更改该属性并再次执行 savechanges()。我终于找到了使用上下文生命周期的正确方法,然后 .AddObject 开始工作了。
  • 所以你整理好了吗?令人困惑的是你仍然说“我想要一种方法来改变那个属性”,如果它是新对象,我很困惑它要改变什么?还是您的意思是您只想设置新对象的一个​​属性,并将其添加到数据库中。如果它是一个新对象,您应该使用.AddObject。那么它排序了吗?
  • 是的,它现在已排序。我的意思是只设置一个属性并将其发送回数据库。
  • 没问题。出于礼貌,请将此作为正确答案接受 - 或者如果您不相信它解决了您的问题,请发布您自己的答案。很高兴你把事情解决了。 :)
猜你喜欢
  • 2011-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-28
相关资源
最近更新 更多