entity framework和SQL Server视图
由于几个我没有自由讨论的理由,我们正在定义一个对我们的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
这个想法是,entity framework将基于这个查询来创build一个实体,但是它会生成一个错误,指出以下内容:
警告6002:表/视图'Keystone_Local.dbo.MeterProvingStatisticsPoint'没有定义主键。 关键是已经被推断出来,定义被创build为只读表/视图。
并且它决定CompletedDateTime字段将是这个实体主键。
我们正在使用EdmGen来生成模型。 有没有办法不让entity framework将这个视图的任何字段作为主键?
我们有同样的问题,这是解决scheme:
要强制entity framework使用列作为主键,请使用ISNULL。
要强制entity framework不要使用列作为主键,请使用NULLIF。
应用这个简单的方法是在另一个select中包装你的视图的select语句。
例:
SELECT ISNULL(MyPrimaryID,-999) MyPrimaryID, NULLIF(AnotherProperty,'') AnotherProperty FROM ( ... ) AS temp
我能用devise师解决这个问题。
- 打开模型浏览器。
- 在图中find视图。
- 右键单击主键,确保选中“实体键”。
- 多选所有的非主键。 使用Ctrl或Shift键。
- 在“属性”窗口中(如果需要查看,请按F4键),将“Entity Key”下拉列表更改为False。
- 保存更改。
- closuresVisual Studio并重新打开它。 我正在使用Visual Studio 2013与EF 6,我不得不这样做,让警告消失。
我不必将我的视图更改为使用ISNULL,NULLIF或COALESCE解决方法。 如果从数据库更新模型,警告将会重新显示,但是如果closures并重新打开VS,将会消失。 您在devise器中所做的更改将保留,不受更新的影响。
同意@Tillito,但是在大多数情况下,它会弄糟SQL优化器,它不会使用正确的索引。
对于某些人来说这可能是显而易见的,但是我花了几个小时来解决使用Tillito解决scheme的性能问题。 比方说你有桌子:
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(至less2008)在计划中包含正确的索引。
如果
这个方法适用于我。 我使用ISNULL()作为主键字段,而COALESCE()如果字段不应该是主键,但也应该有一个不可为空的值。 此示例产生具有不可空的主键的ID字段。 其他字段不是键,并且具有(无)作为它们的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生成器将从视图中的所有非空字段创build一个复合键。 为了获得对此的控制权,您将需要修改视图和基础表列,并在不希望它们成为主键的一部分时将列设置为可为空。 反过来也是如此,正如我所遇到的,EDM生成的关键是导致数据重复的问题,所以我不得不定义一个可为空的列作为非空,以强制EDM中的组合键包含该列。
看起来这是EdmGen已知的问题: http ://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/12aaac4d-2be8-44f3-9448-d7c659585945/
为了得到一个视图,我不得不只显示一个主键列,我创build了第二个视图,指向第一个和使用NULLIF使types为空。 这对我来说使EF认为在视图中只有一个主键。
不知道这是否会帮助你,虽然我不相信EF会接受一个没有主键的实体。
如果您不想混淆将ROW_NUMBER合并到您的select中的主键,并将其设置为主键,并将所有其他列/成员设置为模型中的非主键,那么我也build议您这样做。
由于上述问题,我更喜欢表值函数。
如果你有这个:
CREATE VIEW [dbo].[MyView] AS SELECT A, B FROM dbo.Something
创build这个:
CREATE FUNCTION MyFunction() RETURNS TABLE AS RETURN (SELECT * FROM [dbo].[MyView])
然后,您只需导入该function,而不是视图。