【问题标题】:How do I get Linq to SQL to recognize the result set of a dynamic Stored Procedure?如何让 Linq to SQL 识别动态存储过程的结果集?
【发布时间】:2010-10-04 12:23:22
【问题描述】:

我正在使用带有 SQL Server 后端的 Linq-to-SQL(当然)作为项目的 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

这个程序不是我写的,但如果有一个非常严重的问题,可能会影响更改。

我现在的问题是,当我将这个过程添加到我的模型中时,设计者会生成这个函数:

[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));
}

它看起来不像我手动运行 proc 时得到的结果集:

谁能告诉我这里出了什么问题?

这与this question 基本上是相同的问题,但由于 OP 的措辞不佳,它从未真正得到回答。


感谢马克的回复。我会看看你建议的改变。

问题是临时表。 Linq to Sql 只是不知道如何处理它们。这特别难以诊断,因为 Visual Studio 缓存了有关存储过程的信息,因此当它最初未能找到结果集时,它将返回设置为默认整数类型,并且在我对存储过程进行更改时没有更新。让 VS 识别更改需要您:

  • 从 dbml 中删除 proc
  • 从服务器资源管理器中删除服务器连接
  • 保存 dbml 以强制重新编译
  • 关闭项目并重启VS
  • 重新创建服务器连接并导入过程

您可能不必执行其中的每一个步骤,但这对我有用。如果您必须使用临时表,您需要做的是创建一个准系统 proc,它只返回正确的架构,然后在将其导入 OR 设计器后对其进行更改以执行您想要的操作。

【问题讨论】:

    标签: c# sql sql-server linq-to-sql stored-procedures


    【解决方案1】:

    没有真正简单的方法可以做到这一点。我过去也遇到过同样的问题。我认为问题在于 Linq to Sql 无法“确定”将返回哪种类型,因为您在执行时构建了 SELECT 语句。我为解决这个问题所做的工作是在存储过程中,我只做了一个选择并选择了我可能需要的所有列。然后,我让 Linq to Sql 以此为基础生成函数。然后,我回到 SQL 并将存储过程更改回它应该的方式。这里的诀窍是不要重新生成您的 DBML。

    【讨论】:

      【解决方案2】:

      首先 - 重要 - 你的 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 承担压力……(C#):

      ...
      if(!string.IsNullOrEmpty(author)) {
          query = query.Where(row => row.Author.Contains(author));
      }
      ...
      

      【讨论】:

      猜你喜欢
      • 2010-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-07
      相关资源
      最近更新 更多