C# 如何让LINQtoSQL识别动态存储过程的结果集?
我使用LINQtoSQL和SQLServer后端(当然)作为项目的ORM。我需要从一个从动态创建的表返回的存储过程中获取结果集。以下是程序的外观:C# 如何让LINQtoSQL识别动态存储过程的结果集?,c#,sql,sql-server,linq-to-sql,stored-procedures,C#,Sql,Sql Server,Linq To Sql,Stored Procedures,我使用LINQtoSQL和SQLServer后端(当然)作为项目的ORM。我需要从一个从动态创建的表返回的存储过程中获取结果集。以下是程序的外观: CREATE procedure [RetailAdmin].[TitleSearch] ( @isbn varchar(50), @author varchar(50), @title varchar(50)) as declare @L_isbn varchar(50) declare @l_author varchar(50) declar
CREATE procedure [RetailAdmin].[TitleSearch] (
@isbn varchar(50), @author varchar(50),
@title varchar(50))
as
declare @L_isbn varchar(50)
declare @l_author varchar(50)
declare @l_title varchar(50)
declare @sql nvarchar(4000)
set @L_isbn = rtrim(ltrim(@isbn))
set @l_author = rtrim(ltrim(@author))
set @l_title = rtrim(ltrim(@title))
CREATE TABLE #mytemp(
[storeid] int not NULL,
[Author] [varchar](100) NULL,
[Title] [varchar](400) NULL,
[ISBN] [varchar](50) NULL,
[Imprint] [varchar](255) NULL,
[Edition] [varchar](255) NULL,
[Copyright] [varchar](100) NULL,
[stockonhand] [int] NULL
)
set @sql = 'select a.storeid, Author,Title, thirteendigitisbn ISBN,
Imprint,Edition,Copyright ,b.stockonhand from ods.items a join ods.inventory b on
a.itemkey = b.itemkey where b.stockonhand <> 0 '
if len(@l_author) > 0
set @sql = @sql + ' and author like ''%'+@L_author+'%'''
if len(@l_title) > 0
set @sql = @sql + ' and title like ''%'+@l_title+'%'''
if len(@L_isbn) > 0
set @sql = @sql + ' and thirteendigitisbn like ''%'+@L_isbn+'%'''
print @sql
if len(@l_author) <> 0 or len(@l_title) <> 0 or len(@L_isbn) <> 0
begin
insert into #mytemp
EXECUTE sp_executesql @sql
end
select * from #mytemp
drop table #mytemp
这与我手动运行过程时得到的结果集完全不同:
有人能告诉我这里出了什么问题吗
这基本上与OP的问题相同,但由于OP的措辞不当,它从未真正得到回答
谢谢你的回复。我会考虑做出你建议的改变 问题是临时表。LinqtoSQL只是不知道如何处理它们。这尤其难以诊断,因为VisualStudio缓存有关存储过程的信息,因此当它最初未能找到结果集时,它将返回设置为默认整数类型,并且在我更改存储过程时不会更新。让VS识别更改需要您:
- 从dbml中删除proc
- 从服务器资源管理器中删除服务器连接
- 保存dbml以强制重新编译
- 关闭项目并重新启动VS
- 重新创建服务器连接并导入进程
你可能不必每一步都做,但这对我来说是有效的。如果必须使用临时表,您需要做的是创建一个简单的过程,该过程只返回正确的模式,然后在将其导入或设计器后更改它以执行您想要的操作。没有真正简单的方法可以做到这一点。我过去也有过同样的问题。我认为问题在于LINQtoSQL无法“计算”将返回哪种类型,因为您在执行时正在构建SELECT语句。我所做的就是在存储过程中,选择并选择所有可能需要的列。然后,我让Linq以Sql为基础生成函数。然后,我回到了SQL,并将存储过程改回了它应该的方式。这里的诀窍是不要重新生成DBML 首先-重要-您的SQL易受注入攻击;内部命令应参数化:
if len(@l_author) > 0
set @sql = @sql + ' and author like ''%''+@author+''%'''
EXECUTE sp_executesql @sql, N'@author varchar(100)', @L_author
这会将中的@L_author
值作为动态命令中的@author
参数传递-防止注入攻击
第二,你并不真的需要临时表。它对你没有任何帮助。。。您只需插入并选择。也许只是执行并让结果自然地流向调用方 在其他情况下,表变量更合适,但这不适用于INSERT/EXEC
每个调用的列是否相同?如果是这样,可以手动写入dbml,也可以使用临时SP(仅带有“WHERE 1=0”或其他内容),以便
SET FMT_ONLY ON
可以工作
如果不是(每个用法有不同的列),那么就没有一个简单的答案。在这种情况下,可能使用常规ADO.NET(ExecuteReader
/IDataReader
-甚至可能使用DataTable.Fill
)
当然,你可以让LINQ承受压力。。。(三):
etc前两点对于这个特定的问题很重要,但一般来说,我认为当LINQ to SQL生成的代码没有返回预期结果时,[设置FMTONLY ON][是问题的核心部分。在某些情况下,我将其设置为OFF[当我知道存储的过程不会对数据产生任何影响时,即仅选择]。
if len(@l_author) > 0
set @sql = @sql + ' and author like ''%''+@author+''%'''
EXECUTE sp_executesql @sql, N'@author varchar(100)', @L_author
...
if(!string.IsNullOrEmpty(author)) {
query = query.Where(row => row.Author.Contains(author));
}
...