实体框架和SQL Server视图

Ser*_*ero 131 entity-framework sql-server-2005 primary-key .net-3.5 sql-view

由于几个我无权谈论的原因,我们在Sql Server 2005数据库中定义了一个视图,如下所示:

CREATE VIEW [dbo].[MeterProvingStatisticsPoint]
AS
SELECT
    CAST(0 AS BIGINT) AS 'RowNumber',
    CAST(0 AS BIGINT) AS 'ProverTicketId',
    CAST(0 AS INT) AS 'ReportNumber',
    GETDATE() AS 'CompletedDateTime',
    CAST(1.1 AS float) AS 'MeterFactor',
    CAST(1.1 AS float) AS 'Density',
    CAST(1.1 AS float) AS 'FlowRate',
    CAST(1.1 AS float) AS 'Average',
    CAST(1.1 AS float) AS 'StandardDeviation',
    CAST(1.1 AS float) AS 'MeanPlus2XStandardDeviation',
    CAST(1.1 AS float) AS 'MeanMinus2XStandardDeviation'
WHERE 0 = 1
Run Code Online (Sandbox Code Playgroud)

我们的想法是,实体框架将基于此查询创建一个实体,但它会生成一个包含以下内容的错误:

警告6002:表/视图'Keystone_Local.dbo.MeterProvingStatisticsPoint'没有定义主键.已推断密钥,并将定义创建为只读表/视图.

并且它决定CompletedDateTime字段将是此实体主键.

我们正在使用EdmGen生成模型.有没有办法不让实体框架包含此视图的任何字段作为主键?

Til*_*ito 238

我们遇到了同样的问题,这就是解决方案:

要强制实体框架使用列作为主键,请使用ISNULL.

要强制实体框架不使用列作为主键,请使用NULLIF.

一种简单的方法是将视图的select语句包装在另一个select中.

例:

SELECT
  ISNULL(MyPrimaryID,-999) MyPrimaryID,
  NULLIF(AnotherProperty,'') AnotherProperty
  FROM ( ... ) AS temp
Run Code Online (Sandbox Code Playgroud)

  • 我在这里看到的唯一问题是视图可能合法地需要返回一个空字符串''.我所做的只是简单地将列转换回自己的数据类型.例如,如果AnotherProperty的数据类型为varchar(50),我会将其转换为'CONVERT(VARCHAR(50),AnotherProperty)AS [AnotherProperty]'.这掩盖了EF的可空性,也允许空字符串. (3认同)
  • 我认为这是最好的希望.它起作用的底线. (2认同)
  • 是的,这有助于使EF使用列作为主键isnull(CONVERT(VARCHAR(50),newid()),'')AS [PK] (2认同)
  • 除了在解决方案中只是一个恼人的消息,不解决这个问题有什么害处吗?我同意你的解决方案,但坦率地说我觉得我不应该这样做 - 我想我们都同意这是一个错误吗? (2认同)

Cas*_*mer 66

我能够使用设计师解决这个问题.

  1. 打开模型浏览器.
  2. 在图中查找视图.
  3. 右键单击主键,确保选中"Entity Key".
  4. 多选所有非主键.使用Ctrl或Shift键.
  5. 在"属性"窗口中(如果需要,请按F4查看),将"实体键"下拉列表更改为False.
  6. 保存更改.
  7. 关闭Visual Studio并重新打开它.我正在使用带有EF 6的Visual Studio 2013,我必须这样做才能让警告消失.

我没有必要更改我的视图以使用ISNULL,NULLIF或COALESCE解决方法.如果您从数据库更新模型,警告将重新出现,但如果您关闭并重新打开VS,它将会消失.您在设计器中所做的更改将被保留,并且不会受到刷新的影响.

  • 证实.必须重新启动VS2013以使警告消失. (8认同)
  • "你试过把它关掉再打开吗?" ;-)谢谢,像魅力一样! (4认同)
  • 当我创建视图时,它们甚至不会出现在模型图中.它们在xml文件中被注释 (3认同)
  • 确认VS2017也需要重新启动,以便警告消失. (2认同)

Val*_*tin 45

同意@Tillito,但在大多数情况下,它会破坏SQL优化器,它不会使用正确的索引.

这对某些人来说可能是显而易见的,但是我花了几个小时使用Tillito解决方案来解决性能问题.让我们说你有桌子:

 Create table OrderDetail
    (  
       Id int primary key,
       CustomerId int references Customer(Id),
       Amount decimal default(0)
    );
 Create index ix_customer on OrderDetail(CustomerId);
Run Code Online (Sandbox Code Playgroud)

你的观点是这样的

 Create view CustomerView
    As
      Select 
          IsNull(CustomerId, -1) as CustomerId, -- forcing EF to use it as key
          Sum(Amount) as Amount
      From OrderDetail
      Group by CustomerId
Run Code Online (Sandbox Code Playgroud)

Sql优化器不会使用索引ix_customer,它会对主索引执行表扫描,但是如果不是:

Group by CustomerId
Run Code Online (Sandbox Code Playgroud)

你用

Group by IsNull(CustomerId, -1)
Run Code Online (Sandbox Code Playgroud)

它将使MS SQL(至少2008年)包括正确的索引到计划中.

如果

  • 这家伙的代表是1,他还不能添加评论. (6认同)
  • 这应该是对Tillito答案的评论,而不是答案本身,因为它没有为OP的问题提供解决方案. (2认同)
  • @Contango:这个答案在发布后六天进行了编辑,我发表了评论。查看修订历史。 (2认同)

Spa*_*ude 8

这种方法对我很有用.我使用ISNULL()作为主键字段,如果字段不应该是主键,则使用COALESCE(),但也应该具有不可为空的值.此示例生成具有不可为空的主键的ID字段.其他字段不是键,并且(None)作为Nullable属性.

SELECT      
ISNULL(P.ID, - 1) AS ID,  
COALESCE (P.PurchaseAgent, U.[User Nickname]) AS PurchaseAgent,  
COALESCE (P.PurchaseAuthority, 0) AS PurchaseAuthority,  
COALESCE (P.AgencyCode, '') AS AgencyCode,  
COALESCE (P.UserID, U.ID) AS UserID,  
COALESCE (P.AssignPOs, 'false') AS AssignPOs,  
COALESCE (P.AuthString, '') AS AuthString,  
COALESCE (P.AssignVendors, 'false') AS AssignVendors 
FROM Users AS U  
INNER JOIN Users AS AU ON U.Login = AU.UserName  
LEFT OUTER JOIN PurchaseAgents AS P ON U.ID = P.UserID
Run Code Online (Sandbox Code Playgroud)

如果你真的没有主键,你可以使用ROW_NUMBER来生成一个被代码忽略的伪键.例如:

SELECT
ROW_NUMBER() OVER(ORDER BY A,B) AS Id,
A, B
FROM SOMETABLE
Run Code Online (Sandbox Code Playgroud)


Ann*_*ram 5

当前的实体框架 EDM 生成器将从视图中的所有不可为空字段创建组合键。为了获得对此的控制,当您不希望它们成为主键的一部分时,您需要修改视图和基础表列,将这些列设置为可为空。相反的情况也是如此,正如我遇到的那样,EDM 生成的键导致了数据重复问题,因此我必须将可为空的列定义为不可为空,以强制 EDM 中的复合键包含该列。