无法从实体框架/SQL 服务器获取正确的行
本文关键字:获取 服务器 SQL 实体 框架 | 更新日期: 2023-09-27 18:34:38
我在SQL Server中有一个表:
select * from TaskSave
TaskID SaveTypeID ResultsPath PluginName PluginConfiguration
---------------------------------------------------------------------
92 1 NULL NULL NULL
92 7 NULL RGP_MSWord.WordDocumentOutput www|D:'Users'Peter'Documents'Temp
92 7 NULL RGP_WC.WCOutput wcwc|D:'Users'Peter'Documents'Temp|.docx|123|456|789
我正在尝试使用 C#/实体框架阅读:
public static List<TaskSave> GetSavesPerTask(Task task)
{
using (Entities dbContext = new Entities())
{
var savesPerTask = from p in dbContext.TaskSaves.Include("SaveType").Where(q => q.TaskID == task.TaskID) select p;
//return savesPerTask.ToList();
// DEBUG
var x = savesPerTask.ToList();
foreach (var y in x)
{
Console.WriteLine("SaveTypeID {0}, Plugin Name {1}", y.SaveTypeID, y.PluginName);
}
return x;
}
}
业务规则指出 TaskID + SaveTypeID + PluginName 是唯一的,即一个任务可以有多个插件。如果保存类型不是"插件",则任务 ID + 保存类型ID 必须是唯一的。
我的问题是GetSavesPerTask
方法返回错误的结果。它检索三行,但第 2 行是重复的——我得到 2 行,PluginName
RGP_MSWord.WordDocumentOutput
,而不是RGP_WC.WCOutput
行。调试打印显示:
SaveTypeID 1, Plugin Name
SaveTypeID 7, Plugin Name RGP_MSWord.WordDocumentOutput
SaveTypeID 7, Plugin Name RGP_MSWord.WordDocumentOutput
调试器和数据的最终用户都同意第三行不存在。
我尝试删除包含子句,但这对结果集没有影响。下面是调试器报告的 SQL(来自更简单的情况(:
savesPerTask {SELECT
[Extent1].[TaskID] AS [TaskID],
[Extent1].[SaveTypeID] AS [SaveTypeID],
[Extent1].[ResultsPath] AS [ResultsPath],
[Extent1].[PluginName] AS [PluginName],
[Extent1].[PluginConfiguration] AS [PluginConfiguration]
FROM (SELECT
[TaskSave].[TaskID] AS [TaskID],
[TaskSave].[SaveTypeID] AS [SaveTypeID],
[TaskSave].[ResultsPath] AS [ResultsPath],
[TaskSave].[PluginName] AS [PluginName],
[TaskSave].[PluginConfiguration] AS [PluginConfiguration]
FROM [dbo].[TaskSave] AS [TaskSave]) AS [Extent1]
WHERE [Extent1].[TaskID] = @p__linq__0}
我已经将 SQL 从调试器复制并粘贴到 SSMS 中,它得到了正确的结果。我尝试在 EF 模型中删除并重新创建这两个表。我已经重新编译了很多次,因为我尝试了不同的事情(添加调试、刷新模型、将返回移动到 using 块之外等(。
TaskSave
表没有主键,所以我在编译过程中收到错误 6002(我忽略了它,因为它似乎不会影响其他任何东西,而且我在互联网上找不到任何解决方法(
"Database.dbo.TaskSave"没有定义主键。已推断出键,并将定义创建为只读表/视图。
如何修复返回正确行的GetSavesPerTask
方法?我犯了什么愚蠢的错误?我还有许多其他表和 CRUD 操作,它们似乎按预期工作。
这是我的版本
- .NET 4.6.01055
- C# 2015
- SQL Server 2014
- SQL Server 数据工具 14.0.50730.0
最有可能的是,问题只是缺少显式主键。无论如何,数据库中的每个表都应该有一个主键......
此处发生的情况是:由于没有主键,EF 将仅使用表(或视图(中的所有不可为空的列作为"替换"PK。不确定您的情况是哪些 - 可能(TaskID
,SaveTypeID
(??
当 EF 读取数据时,它将:
- 读取行
- 检查主键(或在这种情况下的"替身"PK(
- 如果它已经读取了具有该PK的行 - 它只是复制它已经拥有的那行 - 它将忽略表/视图中的任何非PK列!
因此,在您的情况下,一旦读取了第一行并TaskID = 92, SaveTypeID = 7
了"替身"PK,则具有这两个值的任何进一步行都将仅获得已读取的值 - 无论数据库中存储了什么!
解决方案:正如我之前所说:每个表都应该有一个适当的主键来唯一标识每一行!
在您的情况下,我建议只添加这样的代理键:
ALTER TABLE dbo.TaskSave
ADD TaskSaveID INT IDENTITY(1,1) NOT NULL
ALTER TABLE dbo.TaskSave
ADD CONSTRAINT PK_YourTableName
PRIMARY KEY CLUSTERED(TaskSaveID)
现在,每一行都有自己唯一的TaskSaveID
,EF可以检测到正确的PK,你所有的麻烦都应该消失了。