如何使用text命令检索参数

时间:2017-05-30 13:22:11

标签: c# sql-server ado.net

我需要找到一种方法来检索以下查询的参数:

query = @"declare @p7 int
          exec some_sproc @SomeArg=@p7
          select @p7";

sqlCommand.CommandText = query;
sqlCommand.CommandType = CommandType.Text;

我厌倦了添加SQL参数,但整个代码只是用exec sp_executesql包装,并添加了参数。这根本行不通。你知道如何在C#方面获得@ p7的价值吗?

我的存储过程使用表值参数,但默认情况下会将其计算为

declare @p11 acco.SomeUDT
insert into @p11 values(1,'2017-06-15 00:00:00',64.73)
insert into @p11 values(1,'2017-06-15 00:00:00',1.30)

但我的目的是获得以下语法:

declare @p11 acco.SomeUDT
insert into @p11 values(1,'2017-06-15 00:00:00',64.73), (1,'2017-06-15 00:00:00',1.30)

这就是我手动构建SQL代码的原因。所以我们有:

query = @"declare @p7 int

          declare @p11 acco.SomeUDT
          insert into @p11 values(1,'2017-06-15 00:00:00',64.73), (1,'2017-06-15 00:00:00',1.30)

          exec some_sproc @SomeArg=@p7, @SomeUDTArg=@p11
          select @p7";
sqlCommand.CommandText = query;
sqlCommand.CommandType = CommandType.Text;

如果我使用存储过程类型和SQL参数,那么比我得到第一个语法。

一切正常,但我需要将参数@SomeArg映射出来,我对此有疑问。

2 个答案:

答案 0 :(得分:0)

您应该能够通过在查询中不声明@ p7,而是将其作为参数添加到SQL CommandText中来实现此目的

query = @"declare @p11 acco.SomeUDT
          insert into @p11 
          values(1,'2017-06-15 00:00:00',64.73), (1,'2017-06-15 00:00:00',1.30)
          exec some_sproc @SomeArg=@p7, @SomeUDTArg=@p11;";

sqlCommand.CommandText = query;
sqlCommand.CommandType = CommandType.Text;
sqlCommand.Parameters.Add("@p7", SqlDbType.Int).Direction = ParameterDirection.Output;
sqlCommand.ExecuteNonQuery();

Console.WriteLine(sqlCommand.Parameters["@p7"].Value);

此外,如果它是您程序中的输出参数,那么您可能应该使用:

exec some_sproc @SomeArg=@p7 OUT, @SomeUDTArg=@p11; 
                             ^^^

修改

如果您对Bobby表,转换问题或构建这样的SQL字符串构成错误的所有原因有任何疑虑,那么可以在c#中创建表并传递它作为参数:

var table = new DataTable();
// TODO: Add the correct column names for your TVP here
table.Columns.Add("Column1", typeof(int));
table.Columns.Add("Column2", typeof(DateTime));
table.Columns.Add("Column3", typeof(decimal));

table.Rows.Add(1, new DateTime(2017, 6, 15), 64.73);
table.Rows.Add(1, new DateTime(2017, 6, 15), 1.3);

sqlCommand.CommandText = "some_sproc";
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.Parameters.Add("@SomeArg", SqlDbType.Int).Direction = ParameterDirection.Output;

var tvp = sqlCommand.Parameters.Add("@SomeUDTArg", SqlDbType.Structured);
tvp.TypeName = "acco.SomeUDT";
tvp.Value = table;

sqlCommand.ExecuteNonQuery();

Console.WriteLine(sqlCommand.Parameters["@SomeArg"].Value);

答案 1 :(得分:0)

此存储过程使用表值参数作为输入并填充输出参数。没有理由在脚本中填写TVP,您可以在客户端填写它。

事实上,这是使用TVP的主要好处之一。在服务器端构建TVP将其抛弃。

sqlCommand.CommandText = "some_sproc";
sqlCommand.CommandType = CommandType.StoredProcedure;

//Create the out parameter
var outParam=sqlCommand.Parameters.Add("@SomeArg", SqlDbType.Int);
outParam.Direction = ParameterDirection.Output;

//Set the TVP value
var tvpParam=sqlCommand.Parameters.Add("@SomeUDTArg",SqlDbType.Structured);
tvpParam.Value=myTable;

//Run it
sqlCommand.ExecuteNonQuery();


//And read the results
var result=outParam.Value;

myTable可以是强类型的DataTable,也可以是在运行时创建的DataTable。我很懒,所以我会使用ToDataTable包中的MoreLinq扩展方法从强类型集合中创建一个DataTable:

public class MyRecord 
{ 
    public int ID{get;set;}
    public DateTime Date {get;set;}
    public decimal Value {get;set;}
    public MyRecord(int id,DateTime date,decimal value){....}
}

...

var myValues=new List<MyRecord>
             {
                 new MyRecord(1,new DateTime(2017,6,15),64.73m),
                 new MyRecord(1,new DateTime(2017,6,15),1.39m)
             };

var myTable=myValues.ToDataTable();

如果UDT的字段名称和属性名称匹配,则无需进行其他更改。

如果要将一组记录用作默认TVP值,则可以创建一次并存储在静态或延迟初始化的字段中。这样,如果没有提供其他参数,您可以创建一个使用默认值的方法:

void DoSomething(IEnumerable<MyRecord> records)
{
    ...
    //Set the TVP value
    var tvpParam=sqlCommand.Parameters.Add("@SomeUDTArg",SqlDbType.Structured);  

    tvpParam.Value=(records==null)?DefaultValues:records.ToDataTable();

    //Run it
    sqlCommand.ExecuteNonQuery();

    ...

}