视图和实体框架数据不正确

本文关键字:数据 不正确 框架 实体 视图 | 更新日期: 2023-09-27 18:32:15

当我从SQL Server Management Studio中的视图中进行选择时,我从某个表中获得了视图,它工作正常,但是当我使用实体框架从视图中获取数据时,情况有所不同。

ReturnDbForTesEntities1 db = new ReturnDbForTesEntities1();
List<VJOBS2> list = new List<VJOBS2>();
list = db.VJOBS2.ToList();

记录数相同,但最后 2 行不同。

我有求职者表格 申请人可以申请2个或更多工作

ApplicantId    ApplicantName  JobId  JobName
   1              Mohamed       1    Developer
   1              Mohamed       2    IT Supporter 

但在列表中

ApplicantId    ApplicantName  JobId  JobName
   1              Mohamed       1    Developer
   1              Mohamed       1    Developer

视图和实体框架数据不正确

从实体框架使用视图时存在一个微妙的问题。

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

对于视图,您没有"主键"的概念 - 视图只包含某些表中的一些列。

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

我不知道这些在你的情况下是什么 - 你应该能够从.edmx模型中看出来。

假设 EF 现在用作"替代"主键的两个不可为空的列(ApplicantId, ApplicantName)。当 EF 读取数据时,它将读取第一行(1, Mohamed, 1, Developer)并为此创建一个对象。

当 EF 读取第二行(1, Mohamed, 2, IT-Supporter)时,它会注意到"主键"(1, Mohamed)与以前相同 - 因此它不会费心创建一个读取这些值的新对象,但主键是相同的,因此它必须是之前已经读取的同一对象,因此它改用该对象。

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

您可以调整 EF 模型以向 EF 明确表示,例如 (ApplicantId, JobId)实际上是主键(您需要确保这些列都不可为空) - 或者您需要在视图中添加诸如"人工"主键之类的内容:

CREATE VIEW dbo.VJOBS2
AS
   SELECT 
       ApplicantId, ApplicantName, JobId, JobName,
       RowNum = ROW_NUMBER() OVER(ORDER BY JobId)
   FROM
       dbo.YourBaseTable

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

仅供参考,我必须添加ISNULL才能让它为我工作,请参阅此代码示例第一行中的修改:

SELECT ISNULL(ROW_NUMBER() OVER(ORDER BY a.OrderItemID),0) as ident, a.* 
FROM
(
      SELECT e.AssignedMachineID, e.StartDate, e.OrderItemID, e2.OrderItemID AS doubleBookedEventID, e.StartTime, e.EndTime, e2.StartTime AS doubleBookedStartDateTime, e2.EndTime AS doubleBookedEndDateTime, DATEDIFF(MINUTE,e2.StartTime,e.EndTime) AS doubleBookedMinutes
  FROM schedule e
    INNER JOIN schedule e2
      ON e.AssignedMachineID = e2.AssignedMachineID
      and e.StartDate=e2.StartDate
      AND e.schedID <> e2.schedID
      AND e2.StartTime BETWEEN DATEADD(minute,1,e.StartTime) AND DateAdd(minute,-1,e.EndTime) where  Coalesce(e.ManuallyOverrided,0)=0 and Coalesce(e.AssignedMachineID,0) > 0
      ) a