首页 文章

实体框架和SQL Server视图

提问于
浏览
127

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

9 回答

  • 2

    由于上面提到的问题,我更喜欢表值函数 .

    如果你有这个:

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

    创造这个:

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

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

  • 1

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

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

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

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

    例:

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

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

    • 打开模型浏览器 .

    • 在图中查找视图 .

    • 右键单击主键,确保选中"Entity Key" .

    • 多选所有非主键 . 使用Ctrl或Shift键 .

    • 在“属性”窗口中(如果需要,请按F4查看),将"Entity Key"下拉列表更改为False .

    • 保存更改 .

    • 关闭Visual Studio并重新打开它 . 我正在使用带有EF 6的Visual Studio 2013,我必须这样做才能让警告消失 .

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

  • 231

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

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

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

    如果

  • 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
    

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

    SELECT
    ROW_NUMBER() OVER(ORDER BY A,B) AS Id,
    A, B
    FROM SOMETABLE
    
  • 4

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

  • 3
  • 63

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

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

  • 45

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

相关问题