由于我无权谈论的几个原因,我们在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来生成模型。有没有办法不让实体框架将此视图的任何字段作为主键?

有帮助吗?

解决方案

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

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

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

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

示例:

SELECT
  ISNULL(MyPrimaryID,-999) MyPrimaryID,
  NULLIF(AnotherProperty,'') AnotherProperty
  FROM ( ... ) AS temp

其他提示

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

  1. 打开模型浏览器。
  2. 查看图表中的视图。
  3. 右键单击主键,并确保“实体键”检查。
  4. 多选所有非主键。使用Ctrl或Shift键。
  5. 在“属性”窗口中(如果需要,请按F4查看),更改 “实体密钥”下拉到假。
  6. 保存更改。
  7. 关闭Visual Studio并重新打开它。我正在使用Visual Studio 2013和EF 6 我不得不这样做才能让警告消失。
  8. 我没有必要更改我的视图以使用ISNULL,NULLIF或COALESCE解决方法。如果您从数据库更新模型,警告将重新出现,但如果您关闭并重新打开VS,它将会消失。您在设计器中所做的更改将被保留,并且不会受到刷新的影响。

同意@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年)包含正确的索引到计划中。

如果

这种方法适合我。我使用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

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

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

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

我还建议,如果您不想弄乱应该将ROW_NUMBER合并到您的选择中的主键,并将其设置为主键,并将所有其他列/成员设置为模型中的非主键。

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

如果你有这个:

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

创建:

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top