无法从Entity Framework / SQL Server获取正确的行

时间:2016-02-13 21:11:09

标签: c# sql-server entity-framework

我在SQL Server中有一个表:

from itertools import count


class Node(object): # if on python3, you don't need to inherit from object

    IDGEN = count()

    def __init__(self, value):
        self.id = self.IDGEN.next()
        ...

我试图用C#/ Entity Framework阅读:

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

业务规则声明TaskID + SaveTypeID + PluginName是唯一的,即任务可以有多个插件。如果保存类型不是“插件”,则TaskID + SaveTypeID必须是唯一的。

我的问题是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; } } 方法返回错误的结果。它检索三行,但第2行是重复的 - 我得到GetSavesPerTask PluginName而不是RGP_MSWord.WordDocumentOutput行的2行。调试打印显示:

RGP_WC.WCOutput

调试器和数据的最终用户都同意第三行不存在。

我尝试删除include子句,但这对结果集没有任何影响。以下是调试器报告的SQL(来自更简单的情况):

SaveTypeID 1, Plugin Name 
SaveTypeID 7, Plugin Name RGP_MSWord.WordDocumentOutput
SaveTypeID 7, Plugin Name RGP_MSWord.WordDocumentOutput

我已将SQL从调试器复制并粘贴到SSMS中,并获得正确的结果。我尝试在EF模型中删除并重新创建这两个表。我已经多次重新编译,因为我尝试了不同的东西(添加调试,刷新模型,将返回移动到使用块之外等)。

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} 表没有主键,所以我在编译期间得到错误6002(我忽略了它,因为它似乎没有影响其他任何东西,我在互联网上找不到任何解决办法)

  

'Database.dbo.TaskSave'没有定义主键。已推断密钥,并将定义创建为只读表/视图。

如何修复TaskSave方法以返回正确的行?我犯了什么愚蠢的错误?我有许多其他表和CRUD操作,似乎按预期工作。

以下是我的版本

  • .NET 4.6.01055
  • C#2015
  • SQL Server 2014
  • SQL Server数据工具14.0.50730.0

1 个答案:

答案 0 :(得分:2)

最有可能,问题只是缺少明确的主键。数据库中的每个表格 无论如何都应该一个主键...

这里发生的事情是:由于没有主键,EF只会使用表格(或视图)中的所有非可空列作为&#34;替换&# 34; PK。不确定你的情况 - 可能(TaskIDSaveTypeID)??

当EF读取数据时,它将会:

  • 阅读行
  • 检查主键(或#34;替换&#34;在这种情况下为PK)
  • 如果已经读取具有该PK的行 - 它只是复制了它已经拥有的那一行 - 它将忽略表中的任何非PK列/视图!

所以在你的情况下,一旦它用&#34;替换&#34;读取第一行。 PK为TaskID = 92, SaveTypeID = 7,具有这两个值的任何其他行只会得到已读取的值 - 无论数据库中存储了什么!

解决方案:正如我之前所说:每个一直一个正确的主键唯一标识每一行!

在您的情况下,我建议只添加这样的代理键:

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,所有的麻烦都应该消失。