无法更新EntitySet - 因为它具有DefiningQuery并且不存在<UpdateFunction>元素

iKo*_*ode 517 .net c# asp.net entity-framework primary-key

我正在使用.net 3.5的Entity Framework 1.

我做的事情很简单:

var RoomDetails = context.Rooms.ToList();

foreach (var Room in Rooms)
{        
   Room.LastUpdated = DateTime.Now;
}
Run Code Online (Sandbox Code Playgroud)

我尝试这样做时收到此错误:

 context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

我收到错误:

无法更新EntitySet - 因为它具有DefiningQuery并且<ModificationFunctionMapping>元素中不存在<UpdateFunction>元素以支持当前操作.

我正在对上下文进行大量更新而没有任何问题,只有当我尝试更新此特定实体时才会这样做.

我所有的搜索都显示了同样的事情,即我正在尝试更新的实体上没有声明主键.但是,我确实有一个主键声明...

Lad*_*nka 984

通常是因为以下原因之一:

  • 实体集从数据库视图映射
  • 自定义数据库查询
  • 数据库表没有主键

执行此操作后,您可能仍需要在停止获取错误之前在Entity Framework设计器中更新(或者删除实体然后添加它).

  • 然后删除并重新创建实体,因为更新在EF设计器中不起作用. (51认同)
  • PK就是答案.谢谢! (45认同)
  • 如果您仍然遇到麻烦,请确保还将store:Schema更改为该EntitySet的Schema. (2认同)
  • @DanielAllenLangdon:是的. (2认同)

小智 86

只需向表中添加主键即可.而已.问题解决了.

ALTER TABLE <TABLE_NAME>
ADD CONSTRAINT <CONSTRAINT_NAME> PRIMARY KEY(<COLUMN_NAME>)
Run Code Online (Sandbox Code Playgroud)

  • 并且不要忘记在.edmx文件上单击"从数据库更新模型" (12认同)

小智 60

这是我的情况.简单地删除导致另一个错误.我按照这篇文章的步骤,除了最后一个.为方便起见,我复制了我所遵循的帖子中的4个步骤来解决问题,如下所示:

  1. 右键单击edmx文件,选择Open with,XML editor
  2. 在edmx:StorageModels元素中找到实体
  3. 完全删除DefiningQuery
  4. 重命名store:Schema="dbo"Schema="dbo"(否则,代码将生成错误,说明名称无效)


Maj*_*jid 40

请注意,您的实体可能具有主键,您的数据库的表没有主键.

  • 无法更改数据库表如何克服? (2认同)

Pha*_*lon 29

更新:我最近得到了一些赞成票,所以我想我会让人们知道我给出的建议不是最好的.由于我最初开始在旧的无钥匙数据库上做实体框架,我已经意识到你可以做的最好的事情是通过反向代码优先做到这一点.关于如何做到这一点,有一些很好的文章.只需按照它们,然后当您想要添加密钥时,使用数据注释来"伪造"密钥.

例如,假设我知道我的桌子Orders,虽然它没有主键,但每个客户只能保证一个订单号.由于这些是表中的前两列,我将代码设置为第一类,如下所示:

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

    [Key, Column(Order = 1)]
    public String Customer { get; set; }
Run Code Online (Sandbox Code Playgroud)

通过这样做,你基本上假装EF相信有一个由OrderNumber和Customer组成的聚簇键.这将允许您在无密钥表上执行插入,更新等操作.

如果你不太熟悉反向Code First,那就去找一个关于Entity Framework Code First的好教程.然后在Reverse Code First(使用现有数据库执行Code First)上找到一个.然后回到这里再看看我的主要建议.:)

原答案:

第一:正如其他人所说,最好的选择是在表中添加主键.完全停止.如果您可以这样做,请不要继续阅读.

但是,如果你不能,或者只是讨厌自己,那么有一种方法可以在没有主键的情况下完成.

就我而言,我正在使用遗留系统(最初在AS400上的平面文件移植到Access,然后移植到T-SQL).所以我必须找到一种方法.这是我的解决方案.以下是使用Entity Framework 6.0(在撰写本文时最新的NuGet)上为我工作的.

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

  2. 寻找像这样的一条线:
    <EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" store:Schema="dbo" store:Name="table_nane">

  3. store:Name="table_name"从最后删除.

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

  5. 看下面那一行并找到<DefiningQuery>标签.它将有一个很大的选择声明.删除标签及其内容.

  6. 现在你的行应该是这样的:
    <EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" Schema="dbo" />

  7. 我们还有其他需要改变的地方.浏览您的文件并找到:
    <EntityType Name="table_name">

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

  9. 下面是<Key>标签.这是实体框架将用于执行插入/更新/删除的内容.所以请你确实这样做.该标记中的属性(或属性)需要指示唯一可识别的行.例如,假设我知道我的桌子orders,虽然它没有主键,但每个客户只能保证一个订单号.

所以我看起来像:

<EntityType Name="table_name">
              <Key>
                <PropertyRef Name="order_numbers" />
                <PropertyRef Name="customer_name" />
              </Key>
Run Code Online (Sandbox Code Playgroud)

说真的,不要做错了.让我们说即使不应该有重复,不知何故,两行进入我的系统,具有相同的订单号和客户名称.Whooops!这就是我没有使用钥匙的原因!所以我使用Entity Framework删除一个.因为我知道副本是今天唯一的订单,所以我这样做:

var duplicateOrder = myModel.orders.First(x => x.order_date == DateTime.Today);
myModel.orders.Remove(duplicateOrder);
Run Code Online (Sandbox Code Playgroud)

你猜怎么着?我刚刚删除了副本和原始版本!那是因为我告诉实体框架,order_number/cutomer_name是我的主键.所以当我告诉它删除duplicateOrder时,它在后台做的是:

DELETE FROM orders
WHERE order_number = (duplicateOrder's order number)
AND customer_name = (duplicateOrder's customer name)
Run Code Online (Sandbox Code Playgroud)

有了那个警告......你现在应该好好去!


mob*_*kie 19

如果数据模型已过期,也会发生这种情况.

希望这会拯救别人的挫折:)


小智 7

如果您的表没有主键,则可能会发生错误,在这种情况下,该表是“只读的”,并且该db.SaveChanges ()命令将始终出错。


Ker*_*lph 6

我得到了相同的错误消息,但在我的场景中,我试图使用PJT(纯连接表)更新从多对多关系派生的实体.

从阅读其他帖子,我想我可以通过在连接表中添加一个额外的PK字段来修复它...但是,如果你将一个PK列添加到连接表,它不再是一个PJT而你会失去所有的实体框架的优点,如实体之间的自动关系映射.

因此,在我的情况下,解决方案是更改数据库上的连接表以生成包含外部ID列的BOTH的PK.


Ali*_*aza 5

设置主键然后保存表和刷新然后去 Model.edmx 删除表并再次获取。