【问题标题】:DefiningQuery and no <DeleteFunction> element exists in the <ModificationFunctionMapping> element to support the current operationDefiningQuery 并且 <ModificationFunctionMapping> 元素中不存在 <DeleteFunction> 元素以支持当前操作
【发布时间】:2012-01-30 09:02:35
【问题描述】:

无法更新 EntitySet 'InstanceObjectName',因为它有一个 DefiningQuery 并且元素中不存在支持当前操作的元素

【问题讨论】:

    标签: c# linq-to-sql entity


    【解决方案1】:

    确保你的表有一个主键!

    【讨论】:

      【解决方案2】:

      实体框架不知道给定视图是否可更新,因此它添加元素以防止框架尝试针对不可更新视图生成查询。

      如果您的视图是可更新的,您只需从 .edmx 的 StorageModel 部分内的视图的 EntitySet 定义中删除该元素,正常的更新处理将与任何其他表一样工作。

      如果您的视图不可更新,您必须自己通过“修改功能映射”提供更新逻辑。修改函数映射调用在 .edmx 的 StorageModel 部分中定义的函数。该函数可能包含数据库中存储过程的名称和参数,或者您可以使用“定义命令”来直接在 .edmx 的 StorageModel 部分的函数定义中编写插入、更新或删除语句.

      在这两个选项中,如果您的视图是可更新的(听起来可能是这样),最简单的方法当然是删除设计者插入的内容。

      【讨论】:

      • 已确认,需要在您的桌子上进行 PK(复合 PK 即可)。删除 DefiningQuery 会使事情变得更糟。
      • 我有这个问题,但是如果我从 EDMX 中删除 DefiningQuery 部分,下次我从 DB 更新模型时会重新生成此部分吗?
      【解决方案3】:

      更新:我最近在这方面得到了一些支持,所以我想我会让人们知道我在下面给出的建议并不是最好的。自从我最初开始在旧的无密钥数据库上做实体框架以来,我已经意识到你能做的最好的事情就是通过反向代码优先来做。有一些关于如何做到这一点的好文章。只需按照它们,然后当您想为其添加密钥时,使用数据注释来“伪造”密钥。

      例如,假设我知道我的表 Orders,虽然它没有主键,但可以确保每个客户只有一个订单号。由于这是表格的前两列,我将代码优先类设置为如下所示:

          [Key, Column(Order = 0)]
          public Int32? OrderNumber { get; set; }
      
          [Key, Column(Order = 1)]
          public String Customer { get; set; }
      

      通过这样做,您基本上是在伪造 EF 以相信存在一个由 OrderNumber 和 Customer 组成的集群键。这将允许您在无密钥表上进行插入、更新等操作。

      如果您对逆向 Code First 不太熟悉,请去找一个关于 Entity Framework Code First 的好教程。然后,一旦您对此感到满意,请在 Reverse Code First 上找到一个(即使用现有数据库执行 Code First)。然后回到这里,再次查看我的关键建议。 :)

      原答案

      首先:正如其他人所说,最好的选择是向表中添加主键。句号。如果您能做到这一点,请不要继续阅读。

      但如果你不能,或者只是讨厌自己,有一种方法可以在没有主键的情况下做到这一点。基本上,我们要做的就是对 Entity Framework 撒谎,告诉它有一个主键。

      就我而言,我使用的是旧系统(最初是 AS400 上的平面文件,移植到 Access,然后移植到 T-SQL)。所以我必须想办法。这是我的解决方案。以下内容对我使用 Entity Framework 6.0(截至本文撰写时 NuGet 的最新版本)有效。

      1. 在解决方案资源管理器中右键单击您的 .edmx 文件。选择“打开方式...”,然后选择“XML(文本)编辑器”。我们将在这里手动编辑自动生成的代码。

      2. 寻找这样的一行:
        &lt;EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" store:Schema="dbo" store:Name="table_nane"&gt;

      3. 从末尾删除store:Name="table_name"

      4. store:Schema="whatever"更改为Schema="whatever"

      5. 查看该行下方并找到&lt;DefiningQuery&gt; 标记。它将有一个很大的选择语句。删除标签及其内容。

      6. 现在您的线路应该如下所示:
        &lt;EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" Schema="dbo" /&gt;

      7. 我们还有一些东西要改变。浏览您的文件并找到以下内容:
        &lt;EntityType Name="table_name"&gt;

      8. 您可能会在附近看到一些注释文本,警告您它没有识别主键,因此已推断出键并且定义是只读表/视图。您可以保留或删除它。我删了。

      9. 下面是&lt;Key&gt; 标签。这就是 Entity Framework 将用来执行插入/更新/删除的内容。所以请确保您做对了。该标记中的属性(或多个属性)需要指示唯一可识别的行。例如,假设我知道我的表orders,虽然它没有主键,但可以确保每个客户只有一个订单号。

      所以我的看起来像:

      <EntityType Name="table_name">
                    <Key>
                      <PropertyRef Name="order_numbers" />
                      <PropertyRef Name="customer_name" />
                    </Key>
      

      说真的,不要做错了。假设即使永远不应该有重复,两行以相同的订单号和客户名称进入我的系统。哎呀!这就是我不使用密钥的结果!所以我使用实体框架删除一个。因为我知道副本是今天发出的唯一订单,所以我这样做:

      var duplicateOrder = myModel.orders.First(x => x.order_date == DateTime.Today);
      myModel.orders.Remove(duplicateOrder);
      

      你猜怎么着?我刚刚删除了副本和原件!那是因为我告诉 Entity Framework order_number/cutomer_name 是我的主键。因此,当我告诉它删除 duplicateOrder 时,它在后台执行的操作类似于:

      DELETE FROM orders
      WHERE order_number = (duplicateOrder's order number)
      AND customer_name = (duplicateOrder's customer name)
      

      有了这个警告……你现在应该可以开始了!

      【讨论】:

        猜你喜欢
        • 2013-02-25
        • 1970-01-01
        • 2011-11-26
        • 2018-09-17
        • 2018-06-30
        • 2011-01-31
        • 1970-01-01
        • 2023-03-16
        • 2017-11-13
        相关资源
        最近更新 更多