Unable to update the EntitySet - because it has a DefiningQuery and no <UpdateFunction> element exist
我正在使用带有.NET 3.5的实体框架1。
我正在做这样简单的事情:
1 2 3 4 5 6 | var RoomDetails = context.Rooms.ToList(); foreach (var Room in Rooms) { Room.LastUpdated = DateTime.Now; } |
当我尝试执行以下操作时,会收到此错误:
1 | context.SaveChanges(); |
号
我得到错误:
Unable to update the EntitySet - because it has a DefiningQuery and no
element exists in the element to support the current operation.
号
我对上下文进行了大量的更新,没有任何问题,只有当我尝试更新这个特定的实体时。
我所有的搜索都显示了相同的事情,即在我试图更新的实体上没有声明主键。但是,我确实声明了一个主键…
通常是因为以下原因之一:
- 实体集从数据库视图映射
- 自定义数据库查询
- 数据库表没有主键
这样做之后,在停止获取错误之前,您可能仍然需要在实体框架设计器中更新(或者删除实体,然后添加它)。
只需向表中添加主键即可。就这样。问题解决了。
1 2 | ALTER TABLE <TABLE_NAME> ADD CONSTRAINT <CONSTRAINT_NAME> PRIMARY KEY(<COLUMN_NAME>) |
我就是这样。简单地删除会导致另一个错误。除了最后一个,我遵循了这篇文章的步骤。为了您的方便,我从文章中复制了以下4个步骤来解决问题:
请注意,您的实体可能有主键,但数据库中的表没有主键。
最新消息:我最近在这个问题上得到了一些支持,所以我想我会让人们知道我下面给出的建议不是最好的。自从我开始在旧的无键数据库上做实体框架的工作以来,我逐渐意识到,到目前为止,你能做的最好的事情就是先反向代码。有几篇关于如何做到这一点的好文章。只需遵循它们,然后当您想要向它添加一个键时,使用数据注释来"伪造"该键。
例如,假设我知道我的表
1 2 3 4 5 | [Key, Column(Order = 0)] public Int32? OrderNumber { get; set; } [Key, Column(Order = 1)] public String Customer { get; set; } |
通过这样做,您基本上被假装成相信有一个由ordernumber和customer组成的集群密钥。这将允许您在无键表上执行插入、更新等操作。
如果您不太熟悉如何先执行逆向代码,请先去寻找一个关于实体框架代码的好教程。然后,首先在逆向代码上找到一个(这是对现有数据库进行代码优先)。然后再回来看看我的建议。:)
原始答案:
第一:正如其他人所说,最好的选择是向表中添加主键。完全停止。如果你能做到这一点,请不要再读下去。
但是如果你不能,或者只是恨你自己,那么有一种方法可以不用主键来完成它。
在我的例子中,我使用的是一个遗留系统(最初是移植到Access的AS400上的平面文件,然后移植到T-SQL)。所以我不得不想办法。这是我的解决方案。以下是使用Entity Framework 6.0(本文撰写时Nuget的最新版本)为我工作的。
右键单击解决方案资源管理器中的.edmx文件。选择"打开方式…",然后选择"XML(文本)编辑器"。我们将在这里手工编辑自动生成的代码。
找一条这样的线:江户十一〔一〕号
从端部拆下
将
看那条线下面,找到
现在您的行应该如下所示:埃多克斯1〔6〕
我们还有别的事情要改变。浏览您的文件并找到:江户十一〔七〕号
在附近,您可能会看到一些注释文本,警告您它没有标识主键,因此已推断出该键,并且定义是只读表/视图。您可以保留或删除它。我删除了它。
下面是
所以我的看起来是:
1 2 3 4 5 | <EntityType Name="table_name"> <Key> <PropertyRef Name="order_numbers" /> <PropertyRef Name="customer_name" /> </Key> |
号
说真的,别做错了。让我们假设,即使不应该有重复的内容,但是有两行以相同的订单号和客户名称进入我的系统。哎呀!这就是我不使用钥匙的原因!所以我用实体框架来删除一个。因为我知道副本是今天唯一的订单,所以我这样做:
1 2 | var duplicateOrder = myModel.orders.First(x => x.order_date == DateTime.Today); myModel.orders.Remove(duplicateOrder); |
你猜怎么着?我刚刚删除了副本和原件!这是因为我告诉实体框架,订单号/客户名称是我的主键。所以当我告诉它删除DuplicateOrder时,它在后台所做的就是:
1 2 3 | DELETE FROM orders WHERE order_number = (duplicateOrder's order number) AND customer_name = (duplicateOrder's customer name) |
。
有了这个警告…你现在该走了!
如果数据模型过时,也可能发生这种情况。
希望这能让其他人免遭挫折:)
我收到了相同的错误消息,但在我的场景中,我试图使用pjt(纯联接表)更新从多对多关系派生的实体。
通过阅读其他文章,我想我可以通过在联接表中添加一个额外的pk字段来修复它…但是,如果将pk列添加到联接表中,它将不再是pjt,并且您将失去所有实体框架的优势,如实体之间的自动关系映射。
所以在我的例子中,解决方案是更改数据库上的join表,以生成包含两个外部ID列的pk。
如果您的表没有主键,则可能会发生错误,在这种情况下,表是"只读的",db.savechanges()命令将始终带来错误
所以这是真的,只需添加一个主键
注意:请确保当您从指向正确数据库的数据库更新EF图时,在我的示例中,连接字符串指向本地数据库,而不是最新的dev db,schoolboy错误,我知道,但我想发布此消息,因为如果您确信添加了主键和你还是会犯同样的错误吗?
设置主键,然后保存表并刷新,然后转到model.edmx删除表并再次获取。
我也有同样的问题。正如这个线程所说,我的表没有pk,所以我设置pk并运行代码。但不幸的是,错误又出现了。接下来,我删除了数据库连接(在解决方案资源管理器的模型文件夹中删除.edmx文件),并重新创建了它。之后错误就消失了。感谢大家分享你的经历。它节省了很多时间。
这不是一个新的答案,但可以帮助那些不确定如何设置表的主键的人。在新查询中使用它并运行。这将把uniqueid列设置为主键。
1 2 3 4 5 6 | USE [YourDatabaseName] GO Alter table [dbo].[YourTableNname] Add Constraint PK_YourTableName_UniqueID Primary Key Clustered (UniqueID); GO |
我之所以会遇到这个问题,是因为我是从现有的数据库(由其他人设计的,我在这里松散地使用术语"designed")生成EDMX的。
结果这张桌子根本没有钥匙。EF正在生成具有多个键的模型。我必须在SQL中向db表添加主键,然后在vs中更新我的模型。
那是给我修的。
添加主键对我也很有用!
完成后,下面介绍如何在不删除数据模型的情况下更新数据模型。-
右键单击EDMX实体设计器页和"从数据库更新模型"。
我也有同样的问题,不幸的是,添加主键并不能解决这个问题。下面是我如何解决我的问题:
问题解决了。
只需向表中添加主键,然后重新创建EF
我只需要从模型中删除表,然后再次更新模型,使表返回。我猜主键是在表被拉入模型之后创建的。
我发现了这个问题,认为是因为我删除了表主键上的索引,并用表中其他一些字段上的索引替换了它。
删除主键索引并刷新EDMX后,插入操作停止工作。
我刷新了旧版本的表,刷新了EDMX,一切都重新工作了。
我应该注意,当我打开EDMX对这个问题进行故障排除时,检查是否定义了主键。所以上面的建议都没有帮助我。但是刷新主键上的索引似乎可以工作。
在XML编辑器中打开.edmx文件,然后从标记中删除标记,并将store:schema="dbo"更改为schema="dbo",然后立即重建解决方案错误将得到解决,您将能够保存数据。