【问题标题】:SQLCLR stored procedures with input parameter带输入参数的 SQLCLR 存储过程
【发布时间】:2016-07-24 04:26:51
【问题描述】:

我对 SQLCLR 存储过程很陌生。在我的示例中,我有两个存储过程,一个没有参数,一个有输入参数。两者都针对相同的表。

没有参数的那一项工作正常,并返回结果中的所有行。但是,即使我没有收到任何错误,具有针对相同表的输入参数的那个也没有返回任何行。 .NET代码中的输入参数设置为SqlString,在数据库中设置为NVARCHAR(50)

这就是我的 C# 代码的样子:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public partial class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void AirlineSqlStoredProcedure (SqlString strAirline)
    {
        SqlConnection conn = new SqlConnection();
        conn.ConnectionString = "Context Connection=true";

        SqlCommand cmd = new SqlCommand();
        cmd.Connection = conn;
        conn.Open();
        cmd.CommandText = "SELECT  dbo.tblAirline.AirlineName, dbo.tblAircraft.AircraftUnits, dbo.tblAircraft.Manufacturer, dbo.tblAircraft.AircraftModel FROM dbo.tblAircraft INNER JOIN dbo.tblAirline ON dbo.tblAircraft.AirlineID = dbo.tblAirline.AirlineID  WHERE AirlineName = '@strAirline' ORDER BY dbo.tblAircraft.AircraftUnits DESC";
        SqlParameter paramAge = new SqlParameter();
        paramAge.Value = strAirline;
        paramAge.Direction = ParameterDirection.Input;
        paramAge.SqlDbType = SqlDbType.NVarChar;
        paramAge.ParameterName = "@strAirline";

        cmd.Parameters.Add(paramAge);
        SqlDataReader sqldr = cmd.ExecuteReader();
        SqlContext.Pipe.Send(sqldr);

        sqldr.Close();
        conn.Close();
    }

    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void AirlineAircraftStoredProcedure()
    {
        //It returns rows from Roles table    
        SqlConnection conn = new SqlConnection();
        conn.ConnectionString = "Context Connection=true";

        SqlCommand cmd = new SqlCommand();
        cmd.Connection = conn;
        cmd.CommandText = "SELECT  dbo.tblAirline.AirlineName, dbo.tblAircraft.AircraftUnits, dbo.tblAircraft.Manufacturer, dbo.tblAircraft.AircraftModel FROM dbo.tblAircraft INNER JOIN dbo.tblAirline ON dbo.tblAircraft.AirlineID = dbo.tblAirline.AirlineID  ORDER BY dbo.tblAircraft.AircraftUnits DESC";
        conn.Open();

        SqlDataReader sqldr = cmd.ExecuteReader();
        SqlContext.Pipe.Send(sqldr);

        sqldr.Close();
        conn.Close();

    }
}

当我执行存储过程时,我得到空行:

USE [TravelSight]
GO

DECLARE @return_value Int

EXEC    @return_value = [dbo].[AirlineSqlStoredProcedure]
        @strAirline = N'American Airlines'

SELECT  @return_value as 'Return Value'

GO

(0 row(s) affected)

(1 row(s) affected)

另外,对于输入参数,我在字符串前面放了一个N

当运行存储过程AirlineAircraftStoredProcedure 以相同的表为目标时,我得到了所有的行:

USE [TravelSight]
GO

DECLARE @return_value Int

EXEC    @return_value = [dbo].[AirlineAircraftStoredProcedure]

SELECT  @return_value as 'Return Value'

GO


(8 row(s) affected)


(1 row(s) affected)

我在这里做错了什么?

【问题讨论】:

  • 也许这些只是示例,但如果不是,为什么这些 CLR 存储过程?看起来您所做的任何事情都没有 CLR 比本机 T-SQL procs 特别好。因此,您会产生开销而没有任何好处。
  • 你是对的,这只是一个学习正确语法的练习。

标签: c# sql-server stored-procedures sqlclr


【解决方案1】:

两个(也许是 3 个)问题:

  1. paramAge.Value = strAirline; 应该是:

    paramAge.Value = strAirline.Value;

    注意.Value 属性的使用。

  2. WHERE AirlineName = '@strAirline'(在 cmd.CommandText = "... 内)应该是:

    WHERE AirlineName = @strAirline

    请注意,查询文本中的单引号已被删除。您只对文字使用单引号,而不是参数/变量。

  3. 替换以下5行:

    SqlParameter paramAge = new SqlParameter();
    paramAge.Value = strAirline;
    paramAge.Direction = ParameterDirection.Input;
    paramAge.SqlDbType = SqlDbType.NVarChar;
    paramAge.ParameterName = "@strAirline";
    

    与:

    SqlParameter paramAge = new SqlParameter("@strAirline", SqlDbType.NVarChar, 50);
    paramAge.Direction = ParameterDirection.Input; // optional as it is the default
    paramAge.Value = strAirline.Value;
    

    请注意,“size”参数是在对new SqlParameter() 的调用中设置的。 始终指定最大字符串长度很重要。

解决了技术问题,还有两个更大的问题需要解决:

  1. 为什么这首先要在 SQLCLR 中完成?没有做任何特定于 .NET 的事情。仅基于问题中发布的代码,这将作为常规的 T-SQL 存储过程更好。

  2. 如果它必须保留在 SQLCLR 中,那么您确实需要将一次性对象包装在 using() 构造中,即:SqlConnectionSqlCommandSqlDataReader。例如:

    using (SqlConnection conn = new SqlConnection("Context Connection=true"))
    {
      using (SqlCommand cmd = conn.CreateCommand())
      {
        ...
      }
    }
    

    然后你不需要以下两行:

    sqldr.Close();
    conn.Close();
    

    因为它们将通过调用它们的每个 Dispose() 方法被隐式调用。

【讨论】:

  • 谢谢,帮了大忙 :) 确实,这不是正确使用 clr 存储过程,只是作为练习尝试一下,稍后我会继续添加一些业务逻辑.再次感谢:)
猜你喜欢
  • 1970-01-01
  • 2014-08-09
  • 1970-01-01
  • 1970-01-01
  • 2018-07-05
  • 1970-01-01
  • 1970-01-01
  • 2020-02-12
  • 1970-01-01
相关资源
最近更新 更多