【问题标题】:entity framework delete issue (with wpf)实体框架删除问题(使用 wpf)
【发布时间】:2011-02-21 23:07:04
【问题描述】:

我有以下问题。我有典型的主/详细 UI 场景。我将主要对象(CommissionPlan)设置为 DataContext。然后我将网格绑定到 CommissionPlanItems(这是子项的集合)

在添加/更新方面一切都很好。当我尝试删除现有行时 - 我收到以下 EF 错误: 无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新的关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。

我发现了一堆关于如何处理这个问题的收据。但我不确定如何在我的情况下执行此操作,因为删除是通过从网格中删除行自动发生的。在这种情况下我应该修改什么?

【问题讨论】:

    标签: c# wpf entity-framework


    【解决方案1】:

    问题在于 WPF 网格仅从 CommissionPlan.CommissionPlanItems 集合中删除项目。在常见情况下,这并不意味着该项目将在数据库中被删除。只有项目之间的关系将被删除,并且 CommisionPlanItem 的 CommissionPlanId 将设置为 null。它是不可为空的,你会得到你的例外。

    解决方案是删除ObjectContext 中已删除的项目或修改您的实体模型以支持identifying relations(我认为只有在Entity Framework 4 中才有可能)。

    【讨论】:

    • 拉迪斯拉夫,我想我现在明白了。从数据库设计的角度来看,修改以支持识别关系似乎不是一个好主意。这个复合键的东西还正常吗?!如何从 ObjectContext 中删除对象?我应该在 SaveChanges 之前搜索它们并执行此操作吗?你有样品吗?就像我说的那样,我无法控制它是如何完成的,因为网格是这样做的。我可能需要在网格之后去“清理”。
    • @katit:我也不喜欢识别关系的想法,但这就是它在 EF 中的工作方式。我不是 WPF 开发人员,所以我通常不确定如何处理它。它通常在ObservableCollection 上执行,您可以在其中处理CollectionChanged 之类的事件。因此,您可能应该将 CommissionPlanItems 包装到 ObservableCollection 中并处理事件。
    【解决方案2】:

    这就是我最终为“清理”所做的事情。我会将其标记为答案,但如果有人给我更好的方法来做到这一点,我将不胜感激。基本上,我正在检查 ObjectStateManager 是否有修改过的实体(有更好的方法来查看这些实体吗?),然后如果我看到修改涉及将父级设置为“null” - 我知道这个实体已从我的图表中“分离”并且我去并删除它。

    modified = context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
                    if (modified != null && modified.Count() > 0)
                    {
                        foreach (ObjectStateEntry ose in modified)
                        {
                            if (
                                (ose.Entity.GetType() == typeof(CommissionPlanCustomer) && ((CommissionPlanCustomer)ose.Entity).CommissionPlan == null)
                                ||
                                (ose.Entity.GetType() == typeof(CommissionPlanItemEligibleUser) && ((CommissionPlanItemEligibleUser)ose.Entity).CommissionPlanItem == null)
                                ||
                                (ose.Entity.GetType() == typeof(CommissionPlanItem) && ((CommissionPlanItem)ose.Entity).CommissionPlan == null)
                               )
                            {
                                context.DeleteObject(ose.Entity);
                            }
                        }
                    }
    

    【讨论】:

      【解决方案3】:

      这里是另一个建议:您可以修改实体模型以支持识别关系,而无需更改数据库设计。然后在 XML 编辑器中打开 edmx 文件并将引用字段添加到关键字段。在这种情况下,它看起来像:

      <edmx:StorageModels>
      <Schema ...>
        ...
        <EntityType Name="CommissionPlanItems">
          <Key>
             <PropertyRef Name="CommissionPlanItemsId" />
             <PropertyRef Name="CommissionPlanId" /> <!-- This line added -->
          </Key>
        ...
        </Schema>
      </edmx:StorageModels>
      <edmx:ConceptualModels>
        <Schema ...>
            ...
           <EntityType Name="CommissionPlanItems">
              <Key>
                <PropertyRef Name="CommissionPlanItemsId" />
                <PropertyRef Name="CommissionPlanId" /> <!-- This line added -->
              </Key>
            ...
        </Schema>
      </edmx:ConceptualModels>
      

      我已经尝试过了,现在可以使用数据网格来插入、删除和更新详细信息项。它可能需要进一步测试。如果您运行“从数据库更新模型”,您可能需要再次编辑 edmx 文件。

      【讨论】:

      • 这是一个最大的问题。我不希望架构在更新时被反转
      【解决方案4】:

      您还可以连接 AssociationChanged 事件以检测 DataGrid 何时删除了 EF 关系。如果您在实体上调用 DeleteObject。 Julie Lerman 在this article 中提供了完整的解释,标题为Drag & Drop Databinding with the Entity Framework and WPF。她随附的视频很好地解释了这项技术(将视频提前到 25 分钟)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-19
        • 1970-01-01
        相关资源
        最近更新 更多