简体   繁体   English

如何将表值参数从 .net 代码传递给存储过程

[英]How to pass table value parameters to stored procedure from .net code

I have a SQL Server 2005 database.我有一个 SQL Server 2005 数据库。 In a few procedures I have table parameters that I pass to a stored proc as an nvarchar (separated by commas) and internally divide into single values.在一些过程中,我将表参数作为nvarchar (以逗号分隔)传递给存储过程,并在内部分为单个值。 I add it to the SQL command parameters list like this:我将它添加到 SQL 命令参数列表中,如下所示:

cmd.Parameters.Add("@Logins", SqlDbType.NVarchar).Value = "jim18,jenny1975,cosmo";

I have to migrate the database to SQL Server 2008. I know that there are table value parameters, and I know how to use them in stored procedures.我必须将数据库迁移到SQL Server 2008。我知道有表值参数,我知道如何在存储过程中使用它们。 But I don't know how to pass one to the parameters list in an SQL command.但我不知道如何将一个传递给 SQL 命令中的参数列表。

Does anyone know correct syntax of the Parameters.Add procedure?有谁知道Parameters.Add过程的正确语法? Or is there another way to pass this parameter?还是有另一种方法来传递这个参数?

DataTable , DbDataReader , or IEnumerable<SqlDataRecord> objects can be used to populate a table-valued parameter per the MSDN article Table-Valued Parameters in SQL Server 2008 (ADO.NET) . DataTableDbDataReaderIEnumerable<SqlDataRecord>对象可用于根据 MSDN 文章SQL Server 2008 (ADO.NET) 中的表值参数填充表值参数。

The following example illustrates using either a DataTable or an IEnumerable<SqlDataRecord> :以下示例说明了使用DataTableIEnumerable<SqlDataRecord>

SQL Code : SQL 代码

CREATE TABLE dbo.PageView
(
    PageViewID BIGINT NOT NULL CONSTRAINT pkPageView PRIMARY KEY CLUSTERED,
    PageViewCount BIGINT NOT NULL
);
CREATE TYPE dbo.PageViewTableType AS TABLE
(
    PageViewID BIGINT NOT NULL
);
CREATE PROCEDURE dbo.procMergePageView
    @Display dbo.PageViewTableType READONLY
AS
BEGIN
    MERGE INTO dbo.PageView AS T
    USING @Display AS S
    ON T.PageViewID = S.PageViewID
    WHEN MATCHED THEN UPDATE SET T.PageViewCount = T.PageViewCount + 1
    WHEN NOT MATCHED THEN INSERT VALUES(S.PageViewID, 1);
END

C# Code : C#代码

private static void ExecuteProcedure(bool useDataTable, 
                                     string connectionString, 
                                     IEnumerable<long> ids) 
{
    using (SqlConnection connection = new SqlConnection(connectionString)) 
    {
        connection.Open();
        using (SqlCommand command = connection.CreateCommand()) 
        {
            command.CommandText = "dbo.procMergePageView";
            command.CommandType = CommandType.StoredProcedure;

            SqlParameter parameter;
            if (useDataTable) {
                parameter = command.Parameters
                              .AddWithValue("@Display", CreateDataTable(ids));
            }
            else 
            {
                parameter = command.Parameters
                              .AddWithValue("@Display", CreateSqlDataRecords(ids));
            }
            parameter.SqlDbType = SqlDbType.Structured;
            parameter.TypeName = "dbo.PageViewTableType";

            command.ExecuteNonQuery();
        }
    }
}

private static DataTable CreateDataTable(IEnumerable<long> ids) 
{
    DataTable table = new DataTable();
    table.Columns.Add("ID", typeof(long));
    foreach (long id in ids) 
    {
        table.Rows.Add(id);
    }
    return table;
}

private static IEnumerable<SqlDataRecord> CreateSqlDataRecords(IEnumerable<long> ids) 
{
    SqlMetaData[] metaData = new SqlMetaData[1];
    metaData[0] = new SqlMetaData("ID", SqlDbType.BigInt);
    SqlDataRecord record = new SqlDataRecord(metaData);
    foreach (long id in ids) 
    {
        record.SetInt64(0, id);
        yield return record;
    }
}

Further to Ryan's answer you will also need to set the DataColumn 's Ordinal property if you are dealing with a table-valued parameter with multiple columns whose ordinals are not in alphabetical order.除了 Ryan 的回答之外,如果您正在处理具有多个列的序数不是按字母顺序排列的table-valued parameter ,您还需要设置DataColumnOrdinal属性。

As an example, if you have the following table value that is used as a parameter in SQL:例如,如果您将下表值用作 SQL 中的参数:

CREATE TYPE NodeFilter AS TABLE (
  ID int not null
  Code nvarchar(10) not null,
);

You would need to order your columns as such in C#:您需要在 C# 中对列进行排序:

table.Columns["ID"].SetOrdinal(0);
// this also bumps Code to ordinal of 1
// if you have more than 2 cols then you would need to set more ordinals

If you fail to do this you will get a parse error, failed to convert nvarchar to int.如果你不这样做,你会得到一个解析错误,无法将 nvarchar 转换为 int。

Generic通用的

   public static DataTable ToTableValuedParameter<T, TProperty>(this IEnumerable<T> list, Func<T, TProperty> selector)
    {
        var tbl = new DataTable();
        tbl.Columns.Add("Id", typeof(T));

        foreach (var item in list)
        {
            tbl.Rows.Add(selector.Invoke(item));

        }

        return tbl;

    }

The cleanest way to work with it.使用它的最干净的方式。 Assuming your table is a list of integers called "dbo.tvp_Int" (Customize for your own table type)假设您的表是一个名为“dbo.tvp_Int”的整数列表(为您自己的表类型定制)

Create this extension method...创建此扩展方法...

public static void AddWithValue_Tvp_Int(this SqlParameterCollection paramCollection, string parameterName, List<int> data)
{
   if(paramCollection != null)
   {
       var p = paramCollection.Add(parameterName, SqlDbType.Structured);
       p.TypeName = "dbo.tvp_Int";
       DataTable _dt = new DataTable() {Columns = {"Value"}};
       data.ForEach(value => _dt.Rows.Add(value));
       p.Value = _dt;
   }
}

Now you can add a table valued parameter in one line anywhere simply by doing this:现在,您只需执行以下操作即可在任意位置的一行中添加表值参数:

cmd.Parameters.AddWithValueFor_Tvp_Int("@IDValues", listOfIds);

Use this code to create suitable parameter from your type:使用此代码从您的类型创建合适的参数:

private SqlParameter GenerateTypedParameter(string name, object typedParameter)
{
    DataTable dt = new DataTable();

    var properties = typedParameter.GetType().GetProperties().ToList();
    properties.ForEach(p =>
    {
        dt.Columns.Add(p.Name, Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType);
    });
    var row = dt.NewRow();
    properties.ForEach(p => { row[p.Name] = (p.GetValue(typedParameter) ?? DBNull.Value); });
    dt.Rows.Add(row);

    return new SqlParameter
    {
        Direction = ParameterDirection.Input,
        ParameterName = name,
        Value = dt,
        SqlDbType = SqlDbType.Structured
    };
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将输入参数从sql表传递到存储过程 - pass input parameters to stored procedure from sql table 如何将表从前端传递到存储过程? - How to pass a table from frontend to a stored procedure? 如何将多个参数传递给 .net core 3.1 上的存储过程 - How to pass multiple parameters to stored procedure on .net core 3.1 如何将存储过程中的大量参数从代码传递到SQL Server - How to pass large number of parameters in stored procedure from code to SQL Server 如何将多个参数从循环传递到SQL Server存储过程 - How to pass multiple parameters from a loop to SQL Server Stored Procedure 如何将表 OBJECT 输出参数从 C# ASP.NET 核心传递到 Z30162ED78B6C10F231411F2F4 - How to pass a TABLE OBJECT out parameter from C# ASP.NET Core to Oracle Stored Procedure 如何从后面的代码运行存储过程(带有参数-有返回值)? - How Run A Stored Procedure (with Parameters - Has A return Value) From Code Behind? 如何将空变量从 C#.net 代码传递给 SQL 存储过程 - How to pass a null variable to a SQL Stored Procedure from C#.net code SSIS如何将表值参数传递到存储过程 - SSIS how to pass Table-Value parameter into stored procedure 如何在后面的代码中将复选框列表的多值传递给存储过程? - How to pass multi value of checkbox list to stored procedure in code behind?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM