我遇到类似
中描述的问题EF can't infer return schema from Stored Procedure selecting from a #temp table
并且我已经基于上述解决方案创建了我的存储过程解决方案但是我仍然遇到类似的EF错误,我真的不知道为什么或理解我如何解决它。
该类型的成员'rowNum'在数据阅读器中没有相应的具有相同名称的列。
我的具体错误:
数据阅读器与指定的'TestModel.sp_SoInfoDocs_Result'不兼容。类型为“rowNum”的成员在数据读取器中没有具有相同名称的相应列。
我的存储过程:
ALTER PROCEDURE [dbo].[sp_SoInfoDocs]
@searchText nvarchar(200),
@PageNumber int,
@PageSize int
AS
BEGIN
IF 1 = 2
BEGIN
SELECT
cast(null as int ) as rowNum
,cast(null as text) as serverName
,cast(null as text) as jobName
,cast(null as DATETIME) as oDate
,cast(null as int) as runCount
,cast(null as nvarchar(10)) as orderID
,cast(null as text) as applicationName
,cast(null as text) as memberName
,cast(null as text) as nodeID
,cast(null as nvarchar(10)) as endStatus
,cast(null as int) as returnCode
,cast(null as DATETIME) as startTime
,cast(null as DATETIME) as endTime
,cast(null as nvarchar(50)) as status
,cast(null as text) as owner
,cast(null as bit) as existsNote
WHERE
1 = 2
END
DECLARE @LowerLimit int;
SET @LowerLimit = (@PageNumber - 1) * @PageSize;
DECLARE @UpperLimit int;
SET @UpperLimit = @PageNumber * @PageSize;
PRINT CAST (@LowerLimit as varchar)
PRINT CAST (@UpperLimit as varchar)
SELECT ROW_NUMBER() over (order by Expr1) as rowNum, *
into #temp
from (
SELECT dbo.SOInfo.jobName, dbo.SOInfo.nodeID, dbo.SOInfo.nodeGroup, dbo.SOInfo.endStatus, dbo.SOInfo.returnCode, dbo.SOInfo.startTime, dbo.SOInfo.endTime,
dbo.SOInfo.oDate, dbo.SOInfo.orderID, dbo.SOInfo.status, dbo.SOInfo.runCount, dbo.SOInfo.owner, dbo.SOInfo.cyclic, dbo.SOInfo.soInfoID, dbo.SOInfo.docInfoID,
dbo.SOInfo.existsNote, dbo.SOInfo.noSysout, dbo.serverInfo.serverName, dbo.Groups.label AS applicationName, Groups_1.label AS memberName,
Groups_2.label AS groupName, Groups_3.label AS scheduleTableName, dbo.SOInfo.serverInfoID, dbo.SOInfo.applicationID, dbo.SOInfo.groupID,
dbo.SOInfo.memberID, dbo.SOInfo.scheduleTableID, dbo.docFile.docFileID, dbo.docInfo.docInfoID AS Expr1, dbo.docFile.docFileObject
FROM dbo.SOInfo INNER JOIN
dbo.serverInfo ON dbo.SOInfo.serverInfoID = dbo.serverInfo.serverInfoID INNER JOIN
dbo.docInfo ON dbo.SOInfo.docInfoID = dbo.docInfo.docInfoID INNER JOIN
dbo.docFile ON dbo.docInfo.docFileID = dbo.docFile.docFileID LEFT OUTER JOIN
dbo.Groups AS Groups_3 ON dbo.SOInfo.scheduleTableID = Groups_3.ID LEFT OUTER JOIN
dbo.Groups AS Groups_1 ON dbo.SOInfo.memberID = Groups_1.ID LEFT OUTER JOIN
dbo.Groups AS Groups_2 ON dbo.SOInfo.groupID = Groups_2.ID LEFT OUTER JOIN
dbo.Groups ON dbo.SOInfo.applicationID = dbo.Groups.ID
WHERE CONTAINS (docfileObject,@searchText)
) tbl
SELECT Count(1) FROM #temp
SELECT rowNum, serverName, jobName ,oDate,runCount,orderID,applicationName,memberName,nodeID, endStatus, returnCode,startTime,endTime,status,owner,existsNote
FROM #temp WHERE rowNum > @LowerLimit AND rowNum <= @UpperLimit
END
我的总体目标是:
搜索聚簇索引表(docInfo)并查找包含特定搜索字符串值的所有行
同时从与每个docInfo对象关联的其他表中捕获元数据
上面的操作(1)和(2)的结果被写入#temp表,然后我添加了rowNum列以使我能够引入分页,即
根据提供的PageNumber和PageSize变量,引入可以在任何时间返回的元数据结果的分页。
做什么
我能够成功创建存储过程。
在SSMS中,我能够成功执行存储过程并提供我期望的结果,这是一个例子
在EF中,我可以通过从数据库更新
来更新和导入存储过程在EF中,我可以看到函数导入,并可以看到映射
在ED中,我可以看到生成的复杂类型
我使用以下代码调用进程
using (TestEntities context = new TestEntities())
{
List<sp_SoInfoDocs_Result> lst = context.sp_SoInfoDocs(searchText, 1, 10).ToList();
}
我编译并运行我的解决方案并从EF
获得以下错误在EntityFramework.SqlServer.dll中发生了'System.Data.Entity.Core.EntityCommandExecutionException'其他信息:数据阅读器与指定的'SysviewModel.sp_SoInfoDocs_Result'不兼容。类型为“rowNum”的成员在数据读取器中没有相应的列具有相同的名称。
对于SSMS / SQL和EF来说,我是一个新手/基本用户,据我所知/可以去,这让我感到很紧张,我真的不知道在哪里转向下一个解决这个问题。
我通过SO广泛搜索,可以看到其他有类似问题的人,并尝试过建议的解决方案,但似乎没有什么对我有用。
我真的非常感谢任何可以帮助我理解的人
这是错的/我做错了吗?
有更好的方法来实现我的需求吗?
关于如何解决这个问题的想法。
提前致谢
答案 0 :(得分:2)
我找到的解决方案是使用SQL临时变量而不是使用临时表,然后使我能够通过最终的SQL Select语句公开表列,然后使用&#34;将它们作为元数据在EF中使用。添加功能导入&#34;功能。
这是我成功工作的一个例子。
USE [TestDB]
GO
/****** Object: StoredProcedure [dbo].[sp_SoInfoDocs_Archive] Script Date: 09/07/2015 10:35:43 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_SoInfoDocs_Archive]
@searchText nvarchar(200),
@PageNumber int,
@PageSize int,
@out int = 0 output
AS
BEGIN
DECLARE @LowerLimit int;
SET @LowerLimit = (@PageNumber - 1) * @PageSize;
DECLARE @UpperLimit int;
SET @UpperLimit = @PageNumber * @PageSize;
-- Create temporary column variables
Declare @temp TABLE
(
rowNum INT,
jobName text,
nodeID nvarchar(50),
nodeGroup text,
endStatus nvarchar(10),
returnCode int,
startTime datetime,
endTime datetime,
oDate smalldatetime,
orderID nvarchar(10),
status nvarchar(50),
runCount int,
owner text,
cyclic text,
soInfoID int,
docInfoID int,
existsNote bit,
noSysout bit,
serverName varchar(256),
applicationName nvarchar(255),
memberName nvarchar(255),
groupName nvarchar(255),
scheduleTableName nvarchar(255),
serverInfoID int,
applicationID int,
groupID int,
memberID int,
scheduleTableID int,
docFileID int,
Expr1 int,
docFileObject varbinary(MAX)
)
INSERT INTO @temp
SELECT ROW_NUMBER() over (order by Expr1) as rowNum, *
from (
SELECT dbo.SOInfoArchive.jobName,
dbo.SOInfoArchive.nodeID,
dbo.SOInfoArchive.nodeGroup,
dbo.SOInfoArchive.endStatus,
dbo.SOInfoArchive.returnCode,
dbo.SOInfoArchive.startTime,
dbo.SOInfoArchive.endTime,
dbo.SOInfoArchive.oDate,
dbo.SOInfoArchive.orderID,
dbo.SOInfoArchive.status,
dbo.SOInfoArchive.runCount,
dbo.SOInfoArchive.owner,
dbo.SOInfoArchive.cyclic,
dbo.SOInfoArchive.soInfoID,
dbo.SOInfoArchive.docInfoID,
dbo.SOInfoArchive.existsNote,
dbo.SOInfoArchive.noSysout,
dbo.serverInfo.serverName,
dbo.Groups.label AS applicationName,
Groups_1.label AS memberName,
Groups_2.label AS groupName,
Groups_3.label AS scheduleTableName,
dbo.SOInfoArchive.serverInfoID,
dbo.SOInfoArchive.applicationID,
dbo.SOInfoArchive.groupID,
dbo.SOInfoArchive.memberID,
dbo.SOInfoArchive.scheduleTableID,
dbo.docFile.docFileID,
dbo.docInfo.docInfoID AS Expr1,
dbo.docFile.docFileObject
FROM dbo.SOInfoArchive INNER JOIN
dbo.serverInfo ON dbo.SOInfoArchive.serverInfoID = dbo.serverInfo.serverInfoID INNER JOIN
dbo.docInfo ON dbo.SOInfoArchive.docInfoID = dbo.docInfo.docInfoID INNER JOIN
dbo.docFile ON dbo.docInfo.docFileID = dbo.docFile.docFileID LEFT OUTER JOIN
dbo.Groups AS Groups_3 ON dbo.SOInfoArchive.scheduleTableID = Groups_3.ID LEFT OUTER JOIN
dbo.Groups AS Groups_1 ON dbo.SOInfoArchive.memberID = Groups_1.ID LEFT OUTER JOIN
dbo.Groups AS Groups_2 ON dbo.SOInfoArchive.groupID = Groups_2.ID LEFT OUTER JOIN
dbo.Groups ON dbo.SOInfoArchive.applicationID = dbo.Groups.ID
WHERE CONTAINS (docfileObject,@searchText)
) tbl
-- Select enables me to consume the following columns as meta data in EF
SELECT rowNum,
serverName,
jobName ,
oDate,
runCount,
orderID,
applicationName,
memberName,
nodeID,
endStatus,
returnCode,
startTime,
endTime,
status,
owner,
existsNote,
docFileID
FROM @temp WHERE rowNum > @LowerLimit AND rowNum <= @UpperLimit
END
所以回顾一下,我现在可以
1)将存储过程导入我的EDMX。
2)&#34;添加功能导入&#34;成功创建
a)sp_SoInfoDocs函数导入
b)sp_SoInfoDocs复杂类型
我现在可以成功调用我的存储过程,如下所示
using (TestEntities context = new TestEntities())
{
string searchText = "rem";
ObjectParameter total = new ObjectParameter("out",typeof(int));
List<sp_SoInfoDocs_Result> lst = context.sp_SoInfoDocs(searchText, 1, 10, total).ToList();
foreach (var item in lst)
{
Console.WriteLine(item.jobName + " " + item.oDate + " " + item.serverName + " " + item.startTime + " " + item.endTime);
}
Console.ReadLine();
}
返回结果的一个例子。
我现在成功地使用此过程的基础在我的View中动态创建的HTML表格中导入和显示元数据。
如果其他人遇到类似的问题而且我没有完全解释为什么我采用了这个解决方案以及我如何使它成功〜那么请随意到P.M.我和我会尽力解释。
答案 1 :(得分:0)
为什么要使用临时表或表变量。表变量有许多performance drawbacks之类:
表变量没有分布统计信息,它们不会 触发重新编译。因此,在许多情况下,优化器将构建 假设表变量没有行的查询计划。 因此,您应该谨慎使用表变量 如果您期望更多行(大于100)。临时表 在这种情况下可能是更好的解决方案。或者,对于查询 将表变量与其他表连接起来,使用RECOMPILE提示, 这将导致优化器使用正确的cardinatlity 表变量。
SQL Server优化器中不支持表变量 基于成本的推理模型。因此,它们不应该在使用时使用 基于成本的选择是实现有效查询计划所必需的。 当需要基于成本的选择时,首选临时表。 这通常包括带连接的查询,并行决策和 索引选择。
修改表变量的查询不会生成并行查询 执行计划。非常大的表时性能会受到影响 复杂查询中的变量或表变量将被修改。在 在这些情况下,请考虑使用临时表。更多 信息,请参阅CREATE TABLE(Transact-SQL)。读表的查询 没有修改它们的变量仍然可以并行化。
使用简单的CTE:
ALTER PROCEDURE [dbo].[sp_SoInfoDocs_Archive]
@searchText NVARCHAR(200),
@PageNumber INT,
@PageSize INT,
@out INT = 0 OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @LowerLimit INT = (@PageNumber - 1) * @PageSize;
DECLARE @UpperLimit INT = @PageNumber * @PageSize;
;WITH cte AS
(
SELECT
dbo.SOInfoArchive.jobName,
dbo.SOInfoArchive.nodeID,
dbo.SOInfoArchive.nodeGroup,
dbo.SOInfoArchive.endStatus,
dbo.SOInfoArchive.returnCode,
dbo.SOInfoArchive.startTime,
dbo.SOInfoArchive.endTime,
dbo.SOInfoArchive.oDate,
dbo.SOInfoArchive.orderID,
dbo.SOInfoArchive.status,
dbo.SOInfoArchive.runCount,
dbo.SOInfoArchive.owner,
dbo.SOInfoArchive.cyclic,
dbo.SOInfoArchive.soInfoID,
dbo.SOInfoArchive.docInfoID,
dbo.SOInfoArchive.existsNote,
dbo.SOInfoArchive.noSysout,
dbo.serverInfo.serverName,
dbo.Groups.label AS applicationName,
Groups_1.label AS memberName,
Groups_2.label AS groupName,
Groups_3.label AS scheduleTableName,
dbo.SOInfoArchive.serverInfoID,
dbo.SOInfoArchive.applicationID,
dbo.SOInfoArchive.groupID,
dbo.SOInfoArchive.memberID,
dbo.SOInfoArchive.scheduleTableID,
dbo.docFile.docFileID,
dbo.docInfo.docInfoID AS Expr1,
dbo.docFile.docFileObject
FROM dbo.SOInfoArchive
JOIN dbo.serverInfo
ON dbo.SOInfoArchive.serverInfoID = dbo.serverInfo.serverInfoID
JOIN dbo.docInfo
ON dbo.SOInfoArchive.docInfoID = dbo.docInfo.docInfoID
JOIN dbo.docFile
ON dbo.docInfo.docFileID = dbo.docFile.docFileID
LEFT JOIN dbo.Groups AS Groups_3
ON dbo.SOInfoArchive.scheduleTableID = Groups_3.ID
LEFT JOIN dbo.Groups AS Groups_1
ON dbo.SOInfoArchive.memberID = Groups_1.ID
LEFT JOIN dbo.Groups AS Groups_2
ON dbo.SOInfoArchive.groupID = Groups_2.ID
LEFT JOIN dbo.Groups
ON dbo.SOInfoArchive.applicationID = dbo.Groups.ID
WHERE CONTAINS (docfileObject,@searchText)
),
cte2 AS
(
SELECT ROW_NUMBER() OVER (ORDER BY Expr1) AS rowNum, *
FROM cte
)
SELECT rowNum,
serverName,
jobName ,
oDate,
runCount,
orderID,
applicationName,
memberName,
nodeID,
endStatus,
returnCode,
startTime,
endTime,
status,
owner,
existsNote,
docFileID
FROM cte2
WHERE rowNum > @LowerLimit
AND rowNum <= @UpperLimit
END
答案 2 :(得分:0)
可能没人在乎了,但是它不起作用的原因是ROW_NUMBER()返回一个BIGINT,并且您的代码以这种方式定义了结构:cast(null as int)as rowNum