none
winforms master detail窗体数据 出错+重复插入 的问题(使用VS2010和Enity Framework 4) RRS feed

  • 问题

  • 两个表

    主表Order

    子表Order Detail

    子表通过外键OrderID和主表的关键字OrderID形成一对多关系

     

    Entity Framework

    通过VS 2010中的设计器,形成两个表的一对多关系

     

    Master Detail 窗体

    1.在VS 2010的Data Source(数据源)窗体中

    拖动Orders表到窗体中,形成一个主Datagridview

    同时在窗体上自动建立一个BindingNavigator 和一个 BindingSource

     

    2.点击数据源窗体中中Order表旁边的+号,并将下面的OrderDetail表拖入窗体,形成一个子Datagridview

    自动建立一个BindingSource

     

    3.在BindingNavigator的保存图标上面点右键,并选择enable以便激活保存图标(不是灰的了)

    此时双击保存按钮,以便输入保存数据的代码,例如db.SaveChanges();

     

    3.在Form Load的事件中为主表的BindingSource.Datasource赋值

    BindingSource.Datasource=db.Orders

     

    4.运行程序

    则主表和子表将分别在窗体中的两个Datagridview中显示

    在主表选择一个记录,子表相应记录可以在另一个Datagridview中显示

     

    5.问题来了

    5.1在主表Datagridview中输入一个新记录,并点保存则出错,其实新的主表记录被保存,出错信息如下:

     

    ”The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.“

     

    5.2在主表Datagridview中输入一个新记录,接着在子表Datagridview中输入相关记录,并点保存,则仍然出错,其实新的主表记录和子表记录均被保存,出错信息如下:

     

    ”The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.“

     

    5.3 将db.SaveChanges()改为db.SaveChanges(Objects.SaveOptions.None)

    则执行5.1时不出错,并且主表中插入了一条新纪录,子表中未插入记录

     

    当执行5.2时,不出错,并且主表中插入了一条新纪录,子表中也插入了相应的记录

     

    当在主表中插入一条新记录,点保存,再在子Datagridview中插入新记录,再点保存,则

    实际上在主表中插入了两条记录

    M1,和M2,两者的唯一差别是主键值不同,其余字段一样

    但是M1没有对应的子表记录

    M2却有对应的子表记录,该记录就是在第二次点保存按钮前在子Datagridview记录中输入的记录

     

     

    我的问题是如何避免在主表中插入两条相同的记录?

    解决在执行db.SaveChanges()时的出错问题

    谢谢

     

     

     






    2011年6月21日 11:58

全部回复

  • 你好,首先我想说一下我对Object.SaveChanges()的理解。

    你用的这个方法db.SaveChanges(Objects.SaveOptions.None) 意思是告诉EF立即保存修改,不触发任何机制。还有两种形式,一个是db.SaveChanges(), 意思是触发自动检测的方法: DetectChanges()  另一个是:db.SaveChanges(Objects.SaveOptions.AcceptAllChangesAfterSave在保存改变完成后会调用AcceptAllChangesAfterSave() 方法。然后改变相应对象的状态。我们一般使用的是db.SaveChanges() 并且也没听说推荐使用其他两种方式的。

    根据你上面的错误信息来看,本来你的主键ID是唯一的,结果是插入数据的时候会出现几条数据有相同的主键。EF在处理这种情况的时候有两种方式,一种是前台生成唯一的主键,另一种是后台数据库生成了唯一的值。 而你这边的原因我想应该是你在后台设定了主键为自增的吧。

    我想你应该试着在你的SSDL中主键属性下加上StoreGeneratedPattern 属性,例如下面在this blogpost引用的代码:

     

    <EntityType Name="Room" Key="ID">

     

       <Property Name="ID" Type="Int32" Nullable="false" StoreGeneratedPattern="identity" />
       <Property Name="Name" Type="String" Nullable="false" MaxLength="50" />
    </EntityType>
    希望能帮到你。

    Jackie Sun [MSFT]
    如果您对我们的论坛在线支持服务有任何的意见或建议,请通过邮件告诉我们。
    MSDN 论坛好帮手 立刻免费下载  MSDN 论坛好帮手
    2011年6月23日 8:05
    版主
  • 您所说的内容似乎是针对早期EF版本的,我目前使用的版本是EF 4。

     

    不知您能否在机器按照我的步骤写一个Winform程序,做一个实验,其实真的只需要7~8分钟时间

     

    SSDL中关于Order表的XML如下图所示:(应该已经符合您所说的要求了,但是在保存时仍然有之前所说的错误)

     

    <EntityType Name="Order">

              <Key>

                <PropertyRef Name="OrderID" />

              </Key>

              <Property Name="OrderID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />

              <Property Name="OrderName" Type="nvarchar" Nullable="false" MaxLength="250" />

              <Property Name="OrderDescription" Type="nvarchar" MaxLength="255" />

    </EntityType>

     

    想得到您的进一步帮助,谢谢。

     



    2011年6月25日 7:30