无法更新EntitySet -因为它有一个DefiningQuery,没有<UpdateFunction>元素存在

我使用实体框架1与。net 3.5。

我做的事情很简单,就像这样:

var roomDetails = context.Rooms.ToList();


foreach (var room in roomDetails)
{
room.LastUpdated = DateTime.Now;
}

当我尝试这样做时,我得到这个错误:

 context.SaveChanges();

我得到了错误:

无法更新EntitySet -因为它有一个DefiningQuery,没有<UpdateFunction>元素存在于<ModificationFunctionMapping>元素来支持当前操作。

我在上下文上做了很多更新,没有任何问题,只有当我试图更新这个特定的实体时。

我所有的搜索结果都是一样的,我要更新的实体上没有声明主键。但是,唉,我有一个主键声明…

382880 次浏览

它的发生通常是由于以下原因之一:

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

这样做之后,您可能仍然需要在实体框架设计器中进行更新(或者删除实体然后添加它),然后才能停止得到错误。

如果数据模型过时,也会发生这种情况。

希望这将避免其他人的沮丧:)

只需向表中添加一个主键。就是这样。问题解决了。

ALTER TABLE <TABLE_NAME>
ADD CONSTRAINT <CONSTRAINT_NAME> PRIMARY KEY(<COLUMN_NAME>)

请注意,也许你的实体have主键,但数据库中的表没有主键

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

通过阅读其他帖子,我认为我可以通过在连接表中添加一个额外的PK字段来修复它……但是,如果您将PK列添加到连接表中,那么它就不再是PJT,您将失去实体框架的所有优势,例如实体之间的自动关系映射。

因此,在我的案例中,解决方案是修改DB上的连接表,使PK包含两个外部ID列。

更新:最近我得到了一些赞,所以我想让人们知道我下面给出的建议不是最好的。自从我最初开始在旧的无键数据库上做实体框架,我已经意识到,到目前为止,你能做的最好的事情是先反向编码。有一些关于如何做到这一点的好文章。只需遵循它们,然后当您想要向它添加一个键时,使用数据注释来“伪造”键。

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

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


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

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

如果你不太熟悉反向代码优先,去找一个关于实体框架代码优先的好教程。然后在“反向编码优先”(即使用现有数据库进行“编码优先”)上找到一个。然后回到这里,再看看我的主要建议。:)

# EYZ0:

首先:正如其他人所说,最好的选择是向表添加一个主键。句号。如果你能做到这一点,就不要再读下去了。

但如果你做不到,或者讨厌自己,也有一种不用主键的方法。

在我的例子中,我使用的是遗留系统(最初是AS400上的平面文件移植到Access,然后移植到T-SQL)。所以我必须想办法。这就是我的解。我使用Entity Framework 6.0(在撰写本文时,NuGet的最新版本)完成了以下工作。

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

  2. 寻找这样的一行:
    李# EYZ0 < / p > < / >

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

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

  5. 查看该行下面,找到<DefiningQuery>标记。它会有一个大的ol' select语句。删除标签及其内容。

  6. 现在你的行应该看起来像这样:
    李# EYZ0 < / p > < / >
  7. 我们还有一些东西要改变。检查你的文件,找到这个:
    李# EYZ0 < / p > < / >

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

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

我的是这样的:

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

说真的,别做错了。让我们假设,尽管不应该有重复的数据,但由于某种原因,有两行数据进入了我的系统,它们具有相同的订单号和客户名称。Whooops !这就是我不用钥匙的后果!所以我使用实体框架删除一个。因为我知道副本是今天唯一的订单,我这样做:

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

你猜怎么着?我刚刚删除了副本和原件!这是因为我告诉实体框架order_number/ customer_name是我的主键。所以当我告诉它删除duplicateOrder时,它在后台做的事情是这样的:

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

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

这是对的,只要加一个主键

# EYZ0

我得到这个问题,因为我正在生成我的EDMX从一个现有的数据库(由别人设计,我使用术语“设计”松散在这里)。

结果发现桌子上根本没有钥匙。EF生成了具有多个键的模型。我必须在SQL中添加一个主键到db表,然后在VS中更新我的模型。

这为我解决了问题。

这就是我的情况。简单地删除会导致另一个错误。我遵循了这篇文章的步骤,除了最后一个。为了您的方便,我从文章中复制了解决问题的4个步骤,如下:

  1. 右键单击edmx文件,选择“使用XML编辑器打开”
  2. 在edmx:StorageModels元素中找到实体
  3. 完全删除DefiningQuery
  4. store:Schema="dbo"重命名为Schema="dbo"(否则,代码将生成一个错误,表示名称无效)

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

我也有同样的问题。正如这个帖子所说,我的表没有PK,所以我设置了PK并运行代码。但不幸的是,错误又来了。我接下来做的是,删除数据库连接(删除解决方案资源管理器的模型文件夹中的。edmx文件)并重新创建它。错误消失了。谢谢大家分享你的经验。这样可以节省很多时间。

添加主键对我也有用!

完成之后,下面是如何在不删除数据模型的情况下更新数据模型

右键单击edmx实体设计器页面和“从数据库更新模型”。

我遇到了完全相同的问题,不幸的是,添加主键并不能解决问题。下面是我的解决方法:

  1. 确保在表上有primary key,这样我就可以修改我的表并添加一个主键。
  2. Delete the ADO.NET Entity Data Model (edmx文件),我用来映射和连接我的数据库。
  3. Add again a new file of ADO.NET Entity Data Model连接我的数据库和映射我的模型属性。
  4. # EYZ0

问题解决了。

只需添加一个主键到您的表,然后重新创建您的EF

我只需要从模型中删除表,并再次更新模型将表带回来。我猜主键是在将表拉入模型之后创建的。

设置主键,然后保存表和刷新,然后去模型。edmx删除表,重新获取。

我有这个问题出现,并相信这是因为我删除了我的表主键上的索引,并将其替换为表中其他一些字段的索引。

在我删除主键索引并刷新edmx后,插入停止工作。

我将表刷新到旧版本,刷新edmx,一切都重新工作了。

我应该指出,当我打开EDMX来解决这个问题时,检查是否定义了一个主键,结果是存在的。所以上面的建议对我都没有帮助。但是刷新主键上的索引似乎有用。

在XML编辑器中打开您的.edmx文件,然后从标签中删除标签,并将store:Schema="dbo"更改为Schema="dbo",重新构建解决方案,现在错误将得到解决,您将能够保存数据。

这不是一个新的答案,但将帮助那些不知道如何设置表的主键的人。在一个新的查询中使用它并运行。这将把UniqueID列设置为主键。

USE [YourDatabaseName]
GO


Alter table  [dbo].[YourTableNname]
Add Constraint PK_YourTableName_UniqueID Primary Key Clustered (UniqueID);
GO
我发现更新.edmx文件的原始答案最适合我的情况。我只是不太喜欢每次从数据库更新模型时都要更改模型。这就是为什么我写了一个额外的文本模板文件,当模型发生变化时自动调用——就像新生成的实体一样。我把它贴在这里的评论里。 为了让它正常工作,请确保将其命名为{model name}.something。Tt,并将其存储在与。edmx文件夹相同的文件夹中。我把它命名为{模型名}. nonpktables .tt。由于第二行中无效的文件扩展名定义,它本身不会生成文件。

<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ output extension="/" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq"#>
<#@ assembly name="%VS120COMNTOOLS%..\IDE\EntityFramework.dll" #>
<#@ assembly name="%VS120COMNTOOLS%..\IDE\Microsoft.Data.Entity.Design.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Windows.Forms" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Data.Entity.Core.Metadata.Edm" #>
<#@ import namespace="System.Data.Entity.Core.Mapping" #>
<#@ import namespace="System.CodeDom" #>
<#@ import namespace="System.CodeDom.Compiler" #>
<#@ import namespace="Microsoft.CSharp"#>
<#@ import namespace="System.Text"#>
<#@ import namespace="System.Diagnostics" #>


<#
string modelFileName= this.Host.TemplateFile.Split('.')[0] + ".edmx";
string edmxPath = this.Host.ResolvePath( modelFileName );


// MessageBox.Show( this.Host.TemplateFile + " applied." );
var modelDoc = XDocument.Load(edmxPath);
var root = modelDoc.Root;
XNamespace nsEdmx = @"http://schemas.microsoft.com/ado/2009/11/edmx";
XNamespace ns = @"http://schemas.microsoft.com/ado/2009/11/edm/ssdl";


var runtime = root.Elements(nsEdmx + "Runtime").First();
var storageModels = runtime.Elements(nsEdmx + "StorageModels").First();
XNamespace nsStore = @"http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator";


var schema = storageModels.Elements(ns + "Schema").First();
XNamespace nsCustomAnnotation = @"http://schemas.microsoft.com/ado/2013/11/edm/customannotation";


var entityTypes = schema.Nodes().OfType<XComment>().Where(c => c.Value.Contains("warning 6002: The table/view"));
bool changed = false;


foreach (var node in entityTypes)
{
var element = node.ElementsAfterSelf().First();
string entityName = element.Attribute("Name").Value;


// Find EntitySet in EntityContainer.
var entityContainer = schema.Elements(ns + "EntityContainer").First();
var entitySet = entityContainer.Elements(ns + "EntitySet").First(s => s.Attribute("Name").Value == entityName);


// Change "store:Schema" attribute to "Schema" attribute.
var attribute = entitySet.Attribute(nsStore + "Schema");


if (attribute != null)
{
string schemaName = entitySet.Attribute(nsStore + "Schema").Value;
entitySet.Attribute(nsStore + "Schema").Remove();
entitySet.Add(new XAttribute("Schema", schemaName));
changed |= true;
}


// Remove the DefiningQuery element.
var definingQuery = entitySet.Element(ns + "DefiningQuery");


if (definingQuery != null)
{
definingQuery.Remove();
changed |= true;
Debug.WriteLine(string.Format("Removed defining query of EntitySet {0}.", entityName));
}
}


if (changed)
modelDoc.Save(edmxPath);
#>

enter image description here

在我的例子中,忘记定义表的主键。因此,像图中所示的那样分配,并从。edmx文件的“Update model from Database”中刷新你的表。 希望能有所帮助!!< / p >

我通过删除和重建EF项目及其所有类来修复它。详情如下:

我在这个问题上转了一个小时,然后删除了包含错误的EF项目,保存了我所有的自定义代码,然后重新构建整个东西。由于这只是生成一个新的EF图及其内部代码的问题,这个修复问题的过程大约花了10分钟。

我怀疑,问题在于生成EF类和属性的数据库优先方法在两次或三次“更新”之后变得有点奇怪。基本上,我在代码行为中发现了一个问题,去修复数据库表属性,然后更新EF图一次太多。然后我试着修改代码,但没有用。

重新开始工作。