Ada*_*sek 8 c# sql sql-server stored-procedures linq-to-sql
我正在使用Linq-to-SQL和SQL Server后端(当然)作为项目的ORM.我需要从一个从动态创建的表返回的存储过程中获取结果集.这是proc的样子:
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
Run Code Online (Sandbox Code Playgroud)
我没有写这个程序,但是如果有一个非常严重的问题,可能会影响一个变化.
我目前的问题是,当我将此过程添加到我的模型时,设计器生成此函数:
[Function(Name="RetailAdmin.TitleSearch")]
public int TitleSearch([Parameter(DbType="VarChar(50)")] string isbn,
[Parameter(DbType="VarChar(50)")] string author,
[Parameter(DbType="VarChar(50)")] string title)
{
IExecuteResult result = this.ExecuteMethodCall(this,
((MethodInfo)(MethodInfo.GetCurrentMethod())), isbn, author, title);
return ((int)(result.ReturnValue));
}
Run Code Online (Sandbox Code Playgroud)
这看起来不像我手动运行proc时得到的结果集:

谁能告诉我这里出了什么问题?
这与这个问题基本上是同一个问题,但是由于OP的措辞不佳,它从未得到过真正的回答.
谢谢Marc的回复.我会看到你提出的改变.
问题是临时表.Linq to Sql只是不知道如何处理它们.这尤其难以诊断,因为Visual Studio会缓存有关存储过程的信息,因此当它最初无法找到结果集时,它会将返回值设置为默认的整数类型,并且在对存储过程进行更改时不会更新.让VS识别更改需要您:
您可能不必执行所有这些步骤,但这对我有用.如果必须使用临时表,则需要做的是创建一个简单返回正确模式的准系统proc,然后在将其导入OR Designer后将其更改为您想要的.
没有真正简单的方法可以做到这一点.我过去也遇到过同样的问题.我认为问题是Linq to Sql无法"搞清楚"因为你在执行时构建SELECT语句将返回哪种类型.我做的是解决这个问题,在存储过程中,我做了一个选择并选择了我可能需要的所有列.然后,我让Linq to 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
Run Code Online (Sandbox Code Playgroud)
这会将@L_authorin 的值作为@author动态命令中的参数传递- 防止注入攻击.
第二 - 你真的不需要临时表.它没有为你做任何事......你只是INSERT和SELECT.也许只是EXEC并让结果自然地流向来电者?
在其他情况下,表变量更合适,但这不适用于INSERT/EXEC.
每次通话的列是否相同?如果是这样,要么手动编写dbml,要么使用临时SP(仅使用"WHERE 1 = 0"或其他东西),以便SET FMT_ONLY ON可以工作.
如果不是(每次使用不同的列),那么就没有一个简单的答案.也许在这种情况下使用常规ADO.NET(ExecuteReader/ IDataReader- 甚至可能DataTable.Fill).
当然,你可以让LINQ承受压力......(C#):
...
if(!string.IsNullOrEmpty(author)) {
query = query.Where(row => row.Author.Contains(author));
}
...
Run Code Online (Sandbox Code Playgroud)
等等