我正在使用带有 .net 3.5 的实体框架 1。
我正在做这样简单的事情:
var roomDetails = context.Rooms.ToList();
foreach (var room in roomDetails)
{
room.LastUpdated = DateTime.Now;
}
当我尝试这样做时出现此错误:
context.SaveChanges();
我得到错误:
无法更新 EntitySet - 因为它有一个 DefiningQuery 并且
我正在对上下文进行大量更新并且没有任何问题,只有当我尝试更新这个特定实体时。
我的所有搜索都显示相同的内容,即我尝试更新的实体上没有声明主键。但是,唉,我确实声明了一个主键......
这通常是由于以下原因之一:
实体集是从数据库视图映射的
自定义数据库查询
数据库表没有主键
这样做之后,您可能仍需要在实体框架设计器中进行更新(或者删除实体然后添加它),然后才能停止收到错误。
只需向表中添加一个主键。而已。问题解决了。
ALTER TABLE <TABLE_NAME>
ADD CONSTRAINT <CONSTRAINT_NAME> PRIMARY KEY(<COLUMN_NAME>)
对我来说就是这种情况。简单地删除导致另一个错误。我按照这篇文章的步骤,除了最后一个。为了您的方便,我复制了我遵循的帖子中的 4 个步骤来解决问题,如下所示:
右击 edmx 文件,选择打开方式,XML 编辑器在 edmx:StorageModels 元素中定位实体 完全移除 DefiningQuery 将 store:Schema="dbo" 重命名为 Schema="dbo" (否则代码会产生错误说名字无效)
请注意,您的实体可能有主键,但您在数据库中的表没有主键。
更新:我最近得到了一些支持,所以我想我会让人们知道我在下面给出的建议并不是最好的。自从我最初开始在旧的无密钥数据库上做实体框架以来,我已经意识到你能做的最好的事情就是通过反向代码优先来做。有一些关于如何做到这一点的好文章。只需按照它们,然后当您想为其添加密钥时,使用数据注释来“伪造”密钥。
例如,假设我知道我的表 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)。然后回到这里,再次查看我的关键建议。 :)
原答案:
第一:正如其他人所说,最好的选择是向表中添加主键。句号。如果你能做到这一点,请不要再读了。
但是如果你不能,或者只是讨厌自己,有一种方法可以在没有主键的情况下做到这一点。
就我而言,我使用的是遗留系统(最初是移植到 Access 的 AS400 上的平面文件,然后移植到 T-SQL)。所以我必须想办法。这是我的解决方案。以下为我使用 Entity Framework 6.0(在撰写本文时 NuGet 上的最新版本)。
在解决方案资源管理器中右键单击您的 .edmx 文件。选择“打开方式...”,然后选择“XML(文本)编辑器”。我们将在这里手动编辑自动生成的代码。寻找这样的一行:
所以我的看起来像:
<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)
有了这个警告......你现在应该很好了!
如果数据模型过时,也会发生这种情况。
希望这可以避免其他人的挫败感:)
我收到了相同的错误消息,但在我的场景中,我试图使用 PJT(纯连接表)更新从多对多关系派生的实体。
通过阅读其他帖子,我想我可以通过在连接表中添加一个额外的 PK 字段来修复它......但是,如果你在连接表中添加一个 PK 列,它就不再是 PJT 并且你失去了所有实体框架的优点,例如实体之间的自动关系映射。
因此,在我的情况下,解决方案是更改数据库上的连接表,以创建一个包含两个外部 ID 列的 PK。
如果您的表没有主键,则可能会发生错误,在这种情况下,该表是“只读”的,db.SaveChanges ()
命令将始终出错。
设置主键,然后保存表并刷新,然后转到 Model.edmx 删除表并再次获取。
所以它是真的,只需添加一个主键
注意:确保当您从指向正确数据库的数据库更新 EF 图时,在我的情况下,连接字符串指向本地数据库而不是最新的 Dev DB,小学生错误我知道,但我想发布这个,因为如果你确信你已经添加了主键并且你仍然得到同样的错误,这可能会非常令人沮丧
我遇到过同样的问题。正如这个帖子所说,我的桌子没有PK,所以我设置了PK并运行了代码。但不幸的是,错误又来了。我接下来要做的是,删除数据库连接(删除解决方案资源管理器的模型文件夹中的 .edmx 文件)并重新创建它。之后错误消失了。感谢大家分享您的经验。它可以节省很多时间。
这不是一个新的答案,但会帮助那些不确定如何为他们的表设置主键的人。在新查询中使用它并运行。这会将 UniqueID 列设置为主键。
USE [YourDatabaseName]
GO
Alter table [dbo].[YourTableNname]
Add Constraint PK_YourTableName_UniqueID Primary Key Clustered (UniqueID);
GO
https://i.stack.imgur.com/mcxpT.png
就我而言,忘记为表定义主键。因此,如图所示分配并从 .edmx 文件中的“从数据库更新模型”刷新您的表。希望它会有所帮助!
我遇到这个问题是因为我从现有数据库(由其他人设计,我在这里松散地使用“设计”一词)生成我的 EDMX。
原来桌子没有任何钥匙。 EF 正在生成具有许多多个键的模型。我必须在 SQL 中向 db 表添加一个主键,然后在 VS 中更新我的模型。
那为我修好了。
添加主键也对我有用!
完成后,以下是如何在不删除数据模型的情况下更新数据模型 -
右键单击 edmx 实体设计器页面和“从数据库更新模型”。
不幸的是,我遇到了完全相同的问题,添加主键并不能解决问题。所以这是我解决我的方法:
确保您在表上有一个主键,以便我更改我的表并添加一个主键。删除用于映射和连接数据库的 ADO.NET 实体数据模型(edmx 文件)。再次添加一个新的 ADO.NET 实体数据模型文件以连接我的数据库并映射我的模型属性。清理并重建解决方案。
问题解决了。
只需向您的表添加一个主键,然后重新创建您的 EF
我只需要从模型中删除表并再次更新模型,将表带回来。我猜主键是在将表拉入模型后创建的。
我遇到了这个问题,并认为这是因为我删除了表主键上的索引并将其替换为表中其他一些字段的索引。
在我删除主键索引并刷新 edmx 后,插入停止工作。
我将表格刷新到旧版本,刷新了 edmx,一切都恢复正常了。
我应该注意到,当我打开 EDMX 来解决这个问题时,检查是否定义了主键,有。所以上述建议都没有帮助我。但是刷新主键上的索引似乎有效。
在 XML 编辑器中打开您的 .edmx 文件,然后从 Tag 中删除标签,并将 store:Schema="dbo" 更改为 Schema="dbo" 并重新构建解决方案,现在错误将解决,您将能够保存数据。
我发现更新 .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);
#>
我通过删除和重建 EF 项目及其所有类来修复它。请参阅下面的详细信息:
我在这个上转了一个小时,然后删除了包含错误的 EF 项目,保存了我所有的自定义代码,然后重建了整个东西。由于只是生成新的 EF 图及其内部代码的问题,因此修复问题的过程大约需要 10 分钟。
我怀疑,问题在于生成 EF 类和属性的数据库优先方法在两三个“更新”之后变得有点奇怪。基本上我发现代码行为有问题,去修复数据库表属性,然后更新EF图一次太多了。然后我尝试摆弄代码,但没有奏效。
重新开始工作。
不定期副业成功案例分享