将 table 值参数传递给具有不同字段数的存储过程
Passing table valued parameter to stored proc with different number of fields
我有一个要求,我需要将 table 值参数传递给存储过程。客户端需要在不影响 C# 代码的情况下向 table 值类型添加字段的灵活性(即使它需要删除并重新创建所有相关存储过程)。是否有可能向 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).
您必须传递一个包含与数据库 table 列相同的列数的数据表。
DataTable myDataTable = new DataTable("MyDataType");
myDataTable.Columns.Add("ID", typeof(Int32));
myDataTable.Columns.Add("Name ", typeof(string));
第一步是通过查询您的 dataBase.INFORMATION_SCHEMA.
来执行查询以获取列的名称和类型
SELECT COLUMN_NAME,DATA_TYPE
FROM yourDataBase.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'yourTableName'
第二步是在循环语句中使用 This result 来构建您需要的数据表,您将把它作为参数发送
Foreach (var item in ColumnsNameType)
{
myDataTable.Columns.Add(item.COLUMN_NAME, typeof(item.COLUMN_NAME));
}
我最终生成数据 table 动态如下:
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;
}
首先获取数据的结构table(你的table类型)
DECLARE @ret yourTableName
SELECT * FROM @ret
然后在 C# 中用您的数据填充它并使用它来调用您的存储过程
我有一个要求,我需要将 table 值参数传递给存储过程。客户端需要在不影响 C# 代码的情况下向 table 值类型添加字段的灵活性(即使它需要删除并重新创建所有相关存储过程)。是否有可能向 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).
您必须传递一个包含与数据库 table 列相同的列数的数据表。
DataTable myDataTable = new DataTable("MyDataType");
myDataTable.Columns.Add("ID", typeof(Int32));
myDataTable.Columns.Add("Name ", typeof(string));
第一步是通过查询您的 dataBase.INFORMATION_SCHEMA.
来执行查询以获取列的名称和类型SELECT COLUMN_NAME,DATA_TYPE
FROM yourDataBase.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'yourTableName'
第二步是在循环语句中使用 This result 来构建您需要的数据表,您将把它作为参数发送
Foreach (var item in ColumnsNameType)
{
myDataTable.Columns.Add(item.COLUMN_NAME, typeof(item.COLUMN_NAME));
}
我最终生成数据 table 动态如下:
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;
}
首先获取数据的结构table(你的table类型)
DECLARE @ret yourTableName
SELECT * FROM @ret
然后在 C# 中用您的数据填充它并使用它来调用您的存储过程