137

由于几个我无权谈论的原因,我们在 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

这个想法是实体框架将基于此查询创建一个实体,它确实这样做了,但它生成它时会出现一个错误,指出以下内容:

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

它决定 CompletedDateTime 字段将是这个实体的主键。

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

4

9 回答 9

253

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

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

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

一种简单的应用方法是将视图的选择语句包装在另一个选择中。

例子:

SELECT
  ISNULL(MyPrimaryID,-999) MyPrimaryID,
  NULLIF(AnotherProperty,'') AnotherProperty
  FROM ( ... ) AS temp
于 2010-04-26T17:00:42.057 回答
68

我能够使用设计器解决这个问题。

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

我不必改变我的观点来使用 ISNULL、NULLIF 或 COALESCE 变通办法。如果您从数据库更新模型,警告将重新出现,但如果您关闭并重新打开 VS,警告就会消失。您在设计器中所做的更改将被保留,并且不受刷新影响。

于 2014-01-18T19:04:28.797 回答
46

同意@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);

你的观点是这样的

 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

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

Group by CustomerId

你用

Group by IsNull(CustomerId, -1)

它将使 MS SQL(至少 2008 年)在计划中包含正确的索引。

如果

于 2012-05-04T19:24:57.167 回答
9

这种方法对我很有效。我对主键字段使用 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

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

SELECT
ROW_NUMBER() OVER(ORDER BY A,B) AS Id,
A, B
FROM SOMETABLE
于 2013-01-29T23:07:46.713 回答
4

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

于 2009-10-07T18:54:56.900 回答
3

看起来这是 EdmGen 的一个已知问题:http: //social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/12aaac4d-2be8-44f3-9448-d7c659585945/

于 2009-06-18T15:55:19.710 回答
3

为了获得一个视图,我只需要显示一个主键列,我创建了第二个视图,它指向第一个视图,并使用 NULLIF 使类型可以为空。这对我有用,让 EF 认为视图中只有一个主键。

不确定这是否会对您有所帮助,因为我不相信 EF 会接受没有主键的实体。

于 2010-02-22T23:02:49.870 回答
3

如果您不想弄乱应该是主键的内容,我建议:

  1. 纳入ROW_NUMBER您的选择
  2. 将其设置为主键
  3. 在模型中将所有其他列/成员设置为非主要的
于 2014-02-25T13:22:19.360 回答
1

由于上述问题,我更喜欢表值函数。

如果你有这个:

CREATE VIEW [dbo].[MyView] AS SELECT A, B FROM dbo.Something

创建这个:

CREATE FUNCTION MyFunction() RETURNS TABLE AS RETURN (SELECT * FROM [dbo].[MyView])

然后您只需导入函数而不是视图。

于 2014-08-03T20:05:28.403 回答