【问题标题】:Using Reflection to Remove Entity from RIA Services EntityCollection?使用反射从 RIA 服务 EntityCollection 中删除实体?
【发布时间】:2010-01-05 16:32:51
【问题描述】:

为了促进控件重用,我们创建了一个包含三个独立项目的解决方案:控件库、Silverlight 客户端和 ASP.NET 后端。控件库没有引用 RIA 服务生成的数据模型类,因此当它需要与之交互时,我们使用反射。

到目前为止,这一切都很好,但我遇到了一个问题。我有一个 DataGrid 控件,用户可以在其中选择一行,按下“删除”按钮,它应该从集合中删除实体。在 DataGrid 类中,我有以下方法:

private void RemoveEntity(Entity entity)
{
    // Use reflection to remove the item from the collection
    Type sourceType = typeof(System.Windows.Ria.EntityCollection<>);
    Type genericType = sourceType.MakeGenericType(entity.GetType());
    System.Reflection.MethodInfo removeMethod = genericType.GetMethod("Remove");
    removeMethod.Invoke(this._dataGrid.ItemsSource, new object[] { entity });

    // Equivalent to: ('Foo' derives from Entity)
    //   EntityCollection<Foo> ec;
    //   ec.Remove(entity);
}

这适用于客户端,但在域服务上,在 Submit() 方法期间会生成以下错误:

"UPDATE 语句与 FOREIGN KEY 约束 “********”。冲突发生在 数据库“********”,表“********”, 柱子 '********'。该声明有 被终止了。”

我注意到的一件事是调用了 UpdateFoo() 服务方法,而不是域服务上的 DeleteFoo() 方法。进一步检查显示实体将进入 ModifiedEntities ChangeSet 而不是 RemovedEntities ChangeSet。我不知道这是否是问题,但它似乎不对。

任何帮助将不胜感激,谢谢,


更新

我确定问题肯定来自对 EntityCollection.Remove() 方法的反射调用。由于某种原因,调用它会导致实体的 EntityState 属性更改为 EntityState.Modified 而不是 EntityState.Deleted。

即使我尝试通过完全绕过 DataGrid 从集合中删除,我也会遇到完全相同的问题:

Entity selectedEntity = this.DataContext.GetType().GetProperty("SelectedEntity").GetValue(this.DataContext, null) as Entity;
object foo = selectedEntity.GetType().GetProperty("Foo").GetValue(selectedEntity, null);
foo.GetType().InvokeMember("Remove", BindingFlags.InvokeMethod, null, foo, new object[] { entity });

作为测试,我尝试修改 UpdateFoo() 域服务方法来实现删除,它成功地删除了实体。这表明 RIA 服务调用工作正常,只是调用了错误的方法(更新而不是删除。)

public void UpdateFoo(Foo currentFoo)
{
    // Original update implementation
    //if ((currentFoo.EntityState == EntityState.Detached))
    //    this.ObjectContext.AttachAsModified(currentFoo, this.ChangeSet.GetOriginal(currentFoo));

    // Delete implementation substituted in
    Foo foo = this.ChangeSet.GetOriginal(currentFoo);
    if ((foo.EntityState == EntityState.Detached))
        this.ObjectContext.Attach(foo);
    this.ObjectContext.DeleteObject(foo);
}

【问题讨论】:

    标签: entity-framework reflection silverlight-3.0 wcf-ria-services


    【解决方案1】:

    我一直在研究类似的问题。

    我认为问题在于您使用 DomainContext 中的 EntityCollections 的引用作为根引用调用 remove,而不是使用 DomainContext 本身作为根。

    所以...

    ParentEntityCollection.EntityCollectionForTEntity.Remove(TEntity);

    生成 EntityState.Modified 而不是 EntityState.Deleted

    试试吧……

    DomainContext.EntityCollectionForTEntity.Remove(TEntity);

    我认为这会产生你想要的结果。

    希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      “外键约束”错误中的“列”是什么?这是网格行和集合中与该列对应的字段吗?您尝试删除的实体是否有可能是行中的列而不是行本身,这会导致更新行(使列为空)而不是删除行?

      【讨论】:

      • 发生有关外键约束的错误是因为调用的是更新例程而不是删除例程,因此此错误并不是真正的根本原因。正如我在更新中指出的那样,将 Delete 方法代码替换为 Update 方法会成功删除记录,因此问题不在于底层 SQL 调用,而在于 Remove 方法如何错误标记 EntityState
      • 我明白了——我的意思是——你认为是行的实体有可能实际上是一列吗?这可以解释为什么在删除时调用更新。因为您会尝试将一列清空而不是删除一行。这里的列是指行中的一个字段。
      • 它所指的列是模型中每个实体的容器类型的ID列。此列存储在实体中并由 EF 管理,但无法直接访问。在非反射情况下,我在获取 DataGrid 的 CurrentItem 并从父集合调用 Remove() 时没有问题。在这种情况下,我仍然使用 CurrentItem 来获取实体,只是我无法直接转换它,因为控件程序集无权访问此类型。回答您的最后一个问题:当我调试时,我看到我传递的实体类型是预期的运行时类型。
      • 是的!终于解决了这个问题!归功于这个答案,因为它引导我朝着正确的方向前进。我所做的只是在数据库中父类型表的 ID 列上关闭“强制外键约束”,然后方法突然成功了。它仍然被标记为已修改而不是已删除(我仍然希望修复),但至少它现在成功地删除和修改了记录。谢谢!!
      【解决方案3】:

      我阅读了您的更新,看来您已经确定问题出在反射上。

      你有没有试过把照片中的倒影去掉?

      如:

      private void RemoveEntity(Entity entity) 
      { 
          // Use reflection to remove the item from the collection 
          Type sourceType = typeof(System.Windows.Ria.EntityCollection<>); 
          Type genericType = sourceType.MakeGenericType(entity.GetType()); 
      
          // Make sure we have the right type
          // and let the framework take care of the proper invoke routine
          if (genericType.IsAssignableFrom(this._dataGrid.ItemsSource.GetType()))
              ((Object) this._dataGrid.ItemsSource).Remove(entity);
      } 
      

      是的,我知道这很丑,但有时...

      编辑添加

      我已更新代码以删除 is 关键字。

      现在关于使用对象来调用 Remove 方法,我相信它可能会因为它的后期绑定而起作用。

      【讨论】:

      • 我看不到任何方法可以在不使用反射的情况下从控制程序集中进行此调用。您的方法将不起作用,因为“is”关键字需要传递显式类型名称,并且“对象”不包含“删除”方法。如果您能想到另一种绕过反射的方法,我非常愿意尝试
      • 这解决了“是”问题,但后期绑定仍然需要一个通用接口才能工作。 IEntityCollection 将是完美的,但看起来 MS 将其限定为“内部”,因此无法在反射之外访问它
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-01
      • 1970-01-01
      • 2011-09-14
      • 1970-01-01
      相关资源
      最近更新 更多