【问题标题】:Passing table valued parameter to stored proc with different number of fields将表值参数传递给具有不同字段数的存储过程
【发布时间】:2019-04-13 17:09:50
【问题描述】:

我有一个要求,我需要将表值参数传递给存储过程。客户端需要在不影响 C# 代码的情况下灵活地将字段添加到表值类型(即使它需要删除和重新创建所有相关的存储过程)。是否可以向 DataTable 添加比数据类型中的列更少的列? 我们使用的是 Microsoft SQL Server 2008 R2。

我试过这个:

SQL:

CREATE TYPE [dbo].[MyDataType] As Table
(
    ID INT NULL,
    Name NVARCHAR(50) NULL
)

CREATE PROCEDURE [dbo].[MyProcedure]
(
    @myData As [dbo].[MyDataType] Readonly
)
AS
Begin
    Select * FROM @myData
End

C#:

DataTable myDataTable = new DataTable("MyDataType");
myDataTable.Columns.Add("Id", typeof(Int32));
myDataTable.Rows.Add(1);
myDataTable.Rows.Add(2);

SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "@myData";
parameter.SqlDbType = System.Data.SqlDbType.Structured;
parameter.Value = myDataTable;
command.Parameters.Add(parameter); 

我收到以下异常:

A first chance exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll
Additional information: Trying to pass a table-valued parameter with 1 column(s) where the corresponding user-defined table type requires 2 column(s).

【问题讨论】:

    标签: c# ado.net


    【解决方案1】:

    您必须传递一个数据表,其列数与数据库表列数相同。

    DataTable myDataTable = new DataTable("MyDataType");
    myDataTable.Columns.Add("ID", typeof(Int32));
    myDataTable.Columns.Add("Name ", typeof(string));
    

    【讨论】:

    • 谢谢,但它没有回答我的问题。
    • 好的!兄弟 。所以你想要一种通用的方式来执行你的程序??
    • 我本可以为此传递 XML,但不幸的是,我目前无法更改存储的过程。
    • 分两步来做这个怎么样。我会把它作为第二个答案,如果它对你有帮助,那就太好了。
    【解决方案2】:

    我最终动态生成数据表如下:

       public static DataTable GetDataTableFromSchema(string userDefinedTableTypeName, SqlConnection connection)
        {
            var query = "SELECT SC.name, ST.name AS datatype FROM sys.columns SC " +
                        "INNER JOIN sys.types ST ON ST.system_type_id = SC.system_type_id AND ST.is_user_defined = 0 " +
                        "WHERE SC.object_id = " +
                        "   (SELECT type_table_object_id FROM sys.table_types WHERE name = '" + userDefinedTableTypeName + "');";
    
            var dataTable = new DataTable();
    
            using (var command = new SqlCommand(query, connection))
            {
                using (var sqlDataReader = command.ExecuteReader())
                {
                    while (sqlDataReader.Read())
                    {
                        var columnName = sqlDataReader["name"].ToString();
                        var sqlDbType = (SqlDbType) Enum.Parse(typeof (SqlDbType), sqlDataReader["datatype"].ToString(), true);
                        var clrType = GetClrType(sqlDbType);
                        dataTable.Columns.Add(columnName, clrType);
                    }
                }                
            }
    
    
            return dataTable;
        }
    

    【讨论】:

    【解决方案3】:

    第一步是通过查询您的 dataBase.INFORMATION_SCHEMA 来执行查询以获取列的名称和类型。

    SELECT COLUMN_NAME,DATA_TYPE 
    FROM yourDataBase.INFORMATION_SCHEMA.COLUMNS
    WHERE  TABLE_NAME = 'yourTableName'
    

    第二步是在循环语句中使用此结果来构建所需的数据表,并将其作为参数发送

    Foreach (var item in ColumnsNameType)
    {
       myDataTable.Columns.Add(item.COLUMN_NAME, typeof(item.COLUMN_NAME));
    }
    

    【讨论】:

      【解决方案4】:

      首先获取数据表的结构(你的表类型)

      DECLARE @ret yourTableName
      SELECT * FROM @ret
      

      然后在 C# 中用你的数据填充它并使用它来调用你的存储过程

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-12
        • 1970-01-01
        • 1970-01-01
        • 2011-07-12
        • 1970-01-01
        • 2016-04-05
        相关资源
        最近更新 更多