带输入参数的 SQLCLR 存储过程
SQLCLR stored procedures with input parameter
我对 SQLCLR 存储过程还很陌生。在我的示例中,我有两个存储过程,一个没有参数,一个有输入参数。两者都针对相同的表。
没有参数的那个工作正常,returns 结果中的所有行。但是,即使我没有收到任何错误,带有针对相同表的输入参数的参数也不会返回任何行。输入参数在.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)
我做错了什么?
两个(也许是 3 个)问题:
paramAge.Value = strAirline;
应该是:
paramAge.Value = strAirline.Value;
注意 .Value
属性.
的使用
WHERE AirlineName = '@strAirline'
(在 cmd.CommandText = "...
内)应该是:
WHERE AirlineName = @strAirline
请注意,查询文本中的单引号已被删除。您只对文字使用单引号,而不是参数/变量。
替换以下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()
的调用中设置的。 始终 指定最大字符串长度很重要。
解决了技术问题后,还有两个更大的问题需要解决:
为什么首先要在 SQLCLR 中完成此操作?没有任何特定于 .NET 的事情正在做。仅基于问题中发布的代码,作为常规 T-SQL 存储过程,这会 多 更好。
如果它必须保留在 SQLCLR 中,那么您确实需要将一次性对象包装在 using()
构造中,即:SqlConnection
、SqlCommand
,和 SqlDataReader
。例如:
using (SqlConnection conn = new SqlConnection("Context Connection=true"))
{
using (SqlCommand cmd = conn.CreateCommand())
{
...
}
}
然后你不需要下面两行:
sqldr.Close();
conn.Close();
因为调用它们的每个 Dispose()
方法都会隐式调用它们。
我对 SQLCLR 存储过程还很陌生。在我的示例中,我有两个存储过程,一个没有参数,一个有输入参数。两者都针对相同的表。
没有参数的那个工作正常,returns 结果中的所有行。但是,即使我没有收到任何错误,带有针对相同表的输入参数的参数也不会返回任何行。输入参数在.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)
我做错了什么?
两个(也许是 3 个)问题:
paramAge.Value = strAirline;
应该是:paramAge.Value = strAirline.Value;
注意
.Value
属性. 的使用
WHERE AirlineName = '@strAirline'
(在cmd.CommandText = "...
内)应该是:WHERE AirlineName = @strAirline
请注意,查询文本中的单引号已被删除。您只对文字使用单引号,而不是参数/变量。
替换以下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()
的调用中设置的。 始终 指定最大字符串长度很重要。
解决了技术问题后,还有两个更大的问题需要解决:
为什么首先要在 SQLCLR 中完成此操作?没有任何特定于 .NET 的事情正在做。仅基于问题中发布的代码,作为常规 T-SQL 存储过程,这会 多 更好。
如果它必须保留在 SQLCLR 中,那么您确实需要将一次性对象包装在
using()
构造中,即:SqlConnection
、SqlCommand
,和SqlDataReader
。例如:using (SqlConnection conn = new SqlConnection("Context Connection=true")) { using (SqlCommand cmd = conn.CreateCommand()) { ... } }
然后你不需要下面两行:
sqldr.Close(); conn.Close();
因为调用它们的每个
Dispose()
方法都会隐式调用它们。