【问题标题】:Insert new object with existing object使用现有对象插入新对象
【发布时间】:2011-03-24 08:04:34
【问题描述】:

我是 EF 4 的新手,这就是我目前所做的:

  • 根据我的数据库创建一个 edmx 文件
  • 为我的对象创建代码生成 (POCO)。现在我有一个 model1.tt,展开后我可以看到我的所有课程
  • 根据 IRepository 为每个类创建一个存储库

现在,我正在使用两个对象,A 和 B。对象 A 具有 B 类型的属性。在我的 winform 中,我有一个包含 B 类型对象的组合。当按下保存按钮时,一个新的实例创建类 A 并设置所有属性。对象B属性设置如下:

objectA.myObjectB = (objectB)cmbBObjects.selectedItem;

然后我为 objectA 创建一个存储库并调用 save 方法。在这个保存方法中,我有这个代码±

public bool Save(ObjectA obj)
{
  using(MyContext context = new MyContext())
  {
    context.objectAs.AddObject(obj);
    context.SaveChanges();
  }
}

这段代码确实在数据库中保存了一个新条目,但它也为对象 B 创建了一条新记录!我不想要这个,因为对象 B 已经存在于数据库中! (我从组合框中选择了这个)。

这就是我填充组合框的方式:

在 objectB 存储库中:

public IList<ObjectB> GetAll()
{
    using(MyContext context = new MyContext())
    {
        IList<ObjectB> objects = context.objectBs.ToList();
        return objects;
    }
}

以我的形式:

ObjectBRepository rep = new ObjectBRepository();
IList<ObjectB> objects = rep.GetAll;

cmbBObjects.Datasource = objects;
// etc..

所以我的问题是,在不为对象 B 创建新记录的情况下,我必须如何保存对象 A?

【问题讨论】:

    标签: c# .net entity-framework entity-framework-4


    【解决方案1】:

    如果您不想插入objectB,您必须通知 EF。当您为 objectA 调用 context.objectAs.AddObject(obj) 时,您是在说:我想插入 objectA 及其所有依赖项。但显然你不想保存依赖项,所以你必须:

    • 在将 objectB 添加到 objectA 之前从 DB 加载它。在这种情况下,EF 会知道 objectB 是现有对象,并且不会再次插入它。
    • 在将objectB 添加到objectA 之前将其附加到上下文。 ObjectB 将被视为现有但未更改。
    • 插入objectA后设置objectB的状态。您可以致电:context.ObjectStateManager.ChangeObjectState(objectB, EntityState.Unchanged)

    第一个建议的例子:

    var id = objectB.Id;
    objectA.myObjectB = context.ObjectBs.SingleOrDefault(o => o.Id == id);
    

    第二个建议的例子:

    context.ObjectBs.Attach(objectB);
    objectA.myObjectB = objectB;
    

    第三个建议的例子:

    objectA.myObjectB = objectB;
    context.ObjectAs.AddObject(objectA);
    context.ObjectStateManager.ChangeObjectState(objectB, EntityState.Unchanged);
    

    【讨论】:

    • 谢谢。没看懂建议1。第二个建议:在objectA的repository中,做如下操作:var obj = context.ObjectB.where(b=&gt; b.Id == objectA.myObjectB.Id).firstOrDefault(); context.ObjectA.Attach(obj); 这样对吗?
    • @LadislavMrnka:没错,所有可能的选项,我认为第二个选项是上述示例的最佳选项。 +1
    • 我尝试了您的第二种解决方案,但略有不同。在我的 ObjectA 存储库的 Save 方法中,我有这个:context.objectBs.Attach(objectA.myObjectB); context.objectAs.AddObject(objectA); context.SaveChanges(); 但是在这里我在context.objectAs.AddObject(objectA); 行有一个关键的已经存在异常,为什么会这样?
    • 您必须先Attach objectB,然后才能将其分配给objectA,否则您将附加两个对象并且您将无法添加objectA
    • @Martijn:您应该在从 dataContext 获取 objectB 后将其附加到 context 并且只有 objectB 而不是 objectA。
    【解决方案2】:

    我认为问题在下一行:

    objectA.myObjectB = (objectB)cmbBObjects.selectedItem;
    

    由于结果(objectB)cmbBObjects.selectedItem 与数据上下文实体框架分离,因此创建了新实例。相反,您可以:

    1.将objectB id分配给objectA

    var b = (objectB)cmbBObjects.selectedItem;
    objectA.myObjectBId = b.Id;
    

    2.或者从dataContext加载objectB,然后分配给objectA:

    var b = (objectB)cmbBObjects.selectedItem;
    var dcB = context.ObjectBs.Single(x=> x.Id == b.Id);
    objectA.myObjectB = dcB;
    

    请尝试我的建议并返回结果,因为我不知道确切。

    希望对您有所帮助。

    【讨论】:

    • objectA 没有直接有objectB id,这个必须设置如下(我想)objectA..myObjectB.Id = b.Id 但是,我认为这会抛出argumentNull 异常,因为.myObjectB 属性没有设置.第二种解决方案:我不认为我希望我的上下文在 winform 中,我想将该对象保留在我的存储库中。
    • @Martijn:好吧,你应该采用我建议的第二种方式(从 dataContext 加载 objectB 并分配给 objectA)。
    猜你喜欢
    • 1970-01-01
    • 2018-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-14
    • 1970-01-01
    • 1970-01-01
    • 2017-10-24
    相关资源
    最近更新 更多