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

时间:2017-10-27 03:26:38

标签: sql-server entity-framework view

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

执行此查询时:

select * 
from HistoryListingView 
order by RequestTime desc`

我得到了这个结果:

4 Row Query Result

但是,在我的控制器中(在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

我看不出有什么可以改变数据。有没有类似记录循环才能获得更好的性能?

2 个答案:

答案 0 :(得分:4)

从Entity Framework使用时,视图存在一个微妙的问题。

如果您有桌子,请将其与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“值,因此没有任何行将被错误地替换为已经从数据库中读取的数据。

答案 1 :(得分:0)

感谢@marc_s的回答,但

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