实体框架从 SQL Server 视图返回不正确的数据

Posted

技术标签:

【中文标题】实体框架从 SQL Server 视图返回不正确的数据【英文标题】:Entity Framework returns incorrect data from SQL Server view 【发布时间】:2017-10-27 03:26:37 【问题描述】:

我有一个包含视图的 SQL Server 数据库。

当我执行这个查询时:

select * 
from HistoryListingView 
order by RequestTime desc`

我得到这个结果:

但是,在我的控制器中(在 ASP.NET MVC 应用程序中),我只执行以下代码:

return Ok(_db.HistoryListingViews.OrderByDescending(r => r.RequestTime));

而且接收到的数据不对应;更准确地说,第 2 行和第 4 行中的 DataType 列不正确,所有其他列似乎都是正确的。

[  
     
      "dataType":"Type de stationnement",
      "actionType":"Obtenir plusieurs entrées",
      "requestTime":"2017-10-26T23:06:43.81",
      "username":"admin",
      "jsonParameters":"[]",
      "error":null,
      "userSessionRequestErrorId":null
   ,
     
      "dataType":"Type de stationnement",
      "actionType":"Obtenir plusieurs entrées",
      "requestTime":"2017-10-26T23:06:43.81",
      "username":"admin",
      "jsonParameters":"[]",
      "error":null,
      "userSessionRequestErrorId":null
   ,
     
      "dataType":"Local",
      "actionType":"Obtenir plusieurs entrées",
      "requestTime":"2017-10-26T23:06:42.687",
      "username":"admin",
      "jsonParameters":"[]",
      "error":null,
      "userSessionRequestErrorId":null
   ,
     
      "dataType":"Local",
      "actionType":"Obtenir plusieurs entrées",
      "requestTime":"2017-10-26T23:06:42.687",
      "username":"admin",
      "jsonParameters":"[]",
      "error":null,
      "userSessionRequestErrorId":null
   
]

我的上下文配置了禁用的lazyLoading 和禁用的ProxyCreation,而我的JsonFormatter (Newtonsoft) 正在使用基本设置:

CamelCasePropertyNamesContractResolver

ReferenceLoopHandling.Ignore

我看不出什么可以改变数据。有没有像记录回收这样的东西来获得更好的性能?

【问题讨论】:

【参考方案1】:

从实体框架中使用时,views 存在一个微妙的问题。

如果您有表,请务必将其与 EF 一起使用,您需要有一个主键来唯一标识每一行。通常,这是一个单列,例如ID 或类似的东西。

对于视图,您没有“主键”的概念 - 视图仅包含来自某些表的一些列。

因此,当 EF 映射视图时,它找不到主键 - 因此,它将使用视图中的所有不可为空的列作为“替代”主键。

我不知道在你的情况下这些是什么 - 你应该能够从 .edmx 模型或从数据库生成的代码类中分辨出来。

查看您的数据,我假设 RequestTime 是您视图中唯一的不可为空的列。 EF 现在将假定这是该视图的“替代”主键。当 EF 去读取数据时,它将读取第一行(“Type de stationnement”)并为那个。

当 EF 读取第二行时,RequestTime相同,因此替代“主键”(RequestTime)与以前相同 - 所以它不会打扰创建读取了这些值的新对象,但主键相同,因此它必须与之前已读取的对象相同,因此它使用该对象。

所以问题真的是你不能在视图上有明确的主键。

您可以调整 EF 模型以使 EF 清楚主键是什么(您需要确保这些列不可为空) - 或者您需要添加类似您视图的“人工”主键:

CREATE VIEW dbo.HistoryListingView 
AS
   SELECT 
       (all the columns you already have in your view),
       RowNum = ROW_NUMBER() OVER(ORDER BY SomeValue)
   FROM
       dbo.YourBaseTable

通过将 RowNum 列添加到您的视图中,该列仅对第 1、2、...、n 行进行编号,您将获得一个新的、不可为空的列,EF 将其包含在“替代 PK”中,并且由于这些数字是连续的,因此不会有两行具有相同的“PK”值,因此不会错误地被已从数据库中读取的内容替换。

【讨论】:

【参考方案2】:

感谢@marc_s 的回答,但是

这对我不起作用,因为 RowNum 仍然可以为空 但是,当我添加 ISNULL(ROW_NUMBER() OVER(ORDER BY SomeValue))

【讨论】:

以上是关于实体框架从 SQL Server 视图返回不正确的数据的主要内容,如果未能解决你的问题,请参考以下文章

实体框架和 SQL Server 视图

实体框架 Code First SQL Server 视图

SQL 服务器视图在实体框架中返回不同的结果

带有实体框架和 SQL Server 数据库的 ASP.NET MVC - 图像未显示在视图中......错误显示“无法将“字节”转换为“字符串”

在实体框架中从 SQL Server 告诉 MySQL

如何从实体框架 DbContext 收集当前的 SQL Server 会话 ID?