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


533

我正在将Entity Framework 1与.net 3.5配合使用。

我正在做这样简单的事情:

var roomDetails = context.Rooms.ToList();

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

我尝试执行此操作时遇到此错误:

 context.SaveChanges();

我得到错误:

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

我正在上下文中进行大量更新,并且没有任何问题,仅当我尝试更新此特定实体时。

我所有的搜索都显示相同的内容,即我要更新的实体上没有声明主键。但是a,我确实声明了主键...


61
我弄错了,桌上没有设置主键,谢谢您的宝贵时间!抱歉给你带来不便!
iKode

1
只是发生在我身上-可能创造1000代表与主键,忘之一-异常消息没有太大的帮助
彼得·芒宁斯

1
优秀的。真的,我忘了给表添加主键。让我们尝试小心一点)
AEMLoviji

Answers:


1022

通常由于以下原因之一而发生:

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

这样做之后,您可能仍需要在停止获取错误之前在Entity Framework设计器中进行更新(或删除该实体然后添加它)。


2
如果仍然遇到问题,请确保也将store:Schema更改为该EntitySet的Schema。
杰夫2012年

53
然后删除并重新创建实体,因为更新在EF设计器中无法正常进行。
Suncat2000

48
答案就是PK。谢谢!
nrod

1
将主键添加到数据库后,EF设计器中的Update对我来说工作正常。使用EF 5.0和.net 4.0
StillLearn

1
同样在这里 !Thx ...不得不删除表并重新添加到EF中才能使用
ajzeffer 2014年

90

只需在表中添加一个主键即可。而已。问题解决了。

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

13
并且不要忘记单击.edmx文件上的“从数据库更新模型”
Bashar Abu Shamaa 2015年

@BasharAbuShamaa如果没有该详细信息,此答案无效。
凯兰·克鲁姆

66

对我来说就是这种情况。简单删除会导致另一个错误。除了上一篇,我按照本文的步骤进行操作。为了方便起见,我复制了解决该问题所遵循的帖子中的4个步骤,如下所示:

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

非常感谢您-这正是解决我的问题的原因。非常令人不安的是,EF中尚未解决此问题。而且,您发现这一点真是太神奇了!
自行车戴夫

我尝试删除该实体并重新添加它。重新编译。清洁。除此之外,对我没有任何帮助。
vintastic

1
这解决了我的问题,但我不知道您是如何想出答案的,以及您的建议为什么可以解决问题。
swcraft

如果需要更新数据库模型会怎样?我做了一个“从数据库更新模型”,这使我的模型完全无法使用。我不得不撤消并重新开始。是否有办法解决?
加里

这是一个很奇怪的问题。是否有任何有关如何避免此问题的信息?尽管如此-它有所帮助
r3dst0rm

41

请注意,也许您的实体具有主键,但是数据库的表却没有主键


1
如果我们不能更改数据库表,该如何克服?
凯·哈特曼

如果可以将数据库表更改为具有主键,则代码生成器将停止犯同样的错误,从EF删除键将导致许多其他问题。
克里斯·谢勒

30

更新:我最近对此有一些反对意见,所以我想让人们知道我在下面给出的建议不是最好的。自从我最初开始考虑在旧的无密钥数据库上执行Entity Framework以来,我逐渐认识到BY FAR可以做的最好的事情就是先进行反向代码。关于如何执行此操作的文章不错。只需跟随它们,然后在要向其添加密钥时,使用数据注释“伪造”密钥。

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

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

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

通过这样做,您基本上是在使EF假装EF认为存在由OrderNumber和Customer组成的集群密钥。这将允许您在无密钥表上进行插入,更新等操作。

如果您不太熟悉执行反向代码优先,请查找关于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>标签。这就是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);

你猜怎么了?我只是删除了重复的和原始的!那是因为我告诉实体框架,order_number / cutomer_name是我的主键。因此,当我告诉它删除duplicateOrder时,它在后台执行的操作类似于:

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

有了那个警告……您现在应该一切顺利!


找到相同的问题解决方案后,找到了这个答案。绝对正确的答案!在许多情况下,仅定义其他答案中提到的主键是无济于事的。
Obl Tobl 2014年

19

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

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


6

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

通过阅读其他文章,我想我可以通过在联接表中添加一个额外的PK字段来解决此问题。但是,如果将PK列添加到联接表中,则它不再是PJT,并且您将失去所有实体框架的优势,例如实体之间的自动关系映射。

因此,在我的情况下,解决方案是更改数据库上的联接表,以创建一个包含两个外部ID列的PK。


这就是生成EDMX一直有效的方式吗?我习惯使用Code First,它不需要纯联接表上的PK。
Michael Hornfeck 2014年

4

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



3

所以它是真的,只需添加一个主键

注意:请确保在从数据库中更新指向正确的数据库的EF图时,在我的情况下,连接字符串指向的是本地数据库而不是最新的开发数据库,​​即男生错误,我知道,但是我想发布此错误,因为如果您确信您已经添加了主键,但是仍然遇到相同的错误,可能会非常沮丧


2

我遇到过同样的问题。就像该线程所说的,我的表没有PK,因此我设置了PK并运行了代码。但是不幸的是错误再次出现。我接下来要做的是,删除数据库连接(在解决方案资源管理器的Model文件夹中删除.edmx文件)并重新创建它。之后错误消失了。感谢大家分享您的经验。节省大量时间。


1

我遇到这个问题是因为我是从现有数据库(由其他人设计的,而在这里我宽松地使用“设计”一词)生成了EDMX。

原来桌子没有任何钥匙。EF正在使用许多多个键来生成模型。我必须在SQL中将主键添加到db表中,然后在VS中更新我的模型。

这为我解决了。


1

这不是一个新的答案,但是可以帮助不确定如何为其表设置主键的人。在新查询中使用它并运行。这会将UniqueID列设置为主键。

USE [YourDatabaseName]
GO

Alter table  [dbo].[YourTableNname]
Add Constraint PK_YourTableName_UniqueID Primary Key Clustered (UniqueID);
GO

1

在此处输入图片说明

就我而言,忘记定义表的主键。因此分配如图所示,并从.edmx文件的“从数据库更新模型”中刷新表。希望它会有所帮助!


0

添加主键也对我有用!

完成此操作后,以下是如何更新数据模型而不删除它的方法-

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


0

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

  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. Clean and rebuild the solution.

问题解决了。



0

我只需要从模型中删除表,然后再次更新模型即可将表重新带回。我猜主键是在将表放入模型后创建的。


0

我遇到了这个问题,并认为是由于我删除了表主键上的Index并将其替换为表中其他某些字段上的索引所引起的。

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

我将表刷新为旧版本,刷新了edmx,然后一切又恢复了。

我应该注意,当我打开EDMX进行故障排除时,请检查是否定义了主键。因此上述建议均无济于事。但是刷新主键上的索引似乎有效。


0

在XML编辑器中打开.edmx文件,然后从“标记”中删除标记,然后将store:Schema =“ dbo”更改为Schema =“ dbo”并重新生成解决方案,现在错误将解决,您将可以保存数据。


0

我发现更新.edmx文件的原始答案在我的情况下效果最好。每次从数据库更新模型时,我只是不太满意更改模型。这就是为什么我编写了一个额外的文本模板文件的原因,该文件在模型更改后会自动调用-就像新生成的实体一样。我在此发表评论。要使其正常工作,请确保将其命名为{model name} .something.tt,并将其存储在与.edmx文件夹相同的文件夹中。我将其命名为{model name} .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);
#>

-1

我在将记录插入具有多对多关系的表中时遇到了同样的错误消息。我的数据库架构是:

Student (Id , Name)
Course (Code , Title),
Student-Course (Student_ID, Course_Code)

学生课程有主键标识和代码分别,而表格学生,课程与学生和课程表映射的两个外键。

从逻辑上讲,该架构是正确的,但是我在数据库中犯了一个错误,因为每个表都应具有主键。

我对Student-Course的 sql定义是:

CREATE TABLE [dbo].[Student-Course] (
    [StudentID]  VARCHAR (12) NOT NULL,
    [CourseCode] VARCHAR (10) NOT NULL,
    CONSTRAINT [FK_Student-Course_ToCourse] FOREIGN KEY ([Course_Code]) REFERENCES [dbo].[Course] ([Code]) ON DELETE CASCADE,
    CONSTRAINT [FK_Student-Course_ToStudent] FOREIGN KEY ([Student_ID]) REFERENCES [dbo].[Student] ([Id]) ON DELETE CASCADE
);

我将外键对作为该表的主键,并更新为:

CREATE TABLE [dbo].[Student-Course] (
    [StudentID]  VARCHAR (12) NOT NULL,
    [CourseCode] VARCHAR (10) NOT NULL,
    CONSTRAINT [PK_Student-Course] PRIMARY KEY CLUSTERED ([Student_ID] ASC, [Course_Code] ASC),
    CONSTRAINT [FK_Student-Course_ToCourse] FOREIGN KEY ([Course_Code]) REFERENCES [dbo].[Course] ([Code]) ON DELETE CASCADE,
    CONSTRAINT [FK_Student-Course_ToStudent] FOREIGN KEY ([Student_ID]) REFERENCES [dbo].[Student] ([Id]) ON DELETE CASCADE
);

希望它能为某些人解决问题。


这个问题已经有太多答案了。此外,几乎每个回答说“添加主键”和一个做它在许多一对多的情况下。
Gert Arnold
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.