How to pass a table-value parameter

前端 未结 3 822
谎友^
谎友^ 2020-11-28 11:54

I am trying to pass a table-value parameter to a stored procedure, but I keep getting an exception (see below).

SqlCommand c = new SqlCommand(\"getPermittedU         


        
相关标签:
3条回答
  • 2020-11-28 12:10

    Adding a new answer with updated links.

    According to the documentation (docs.microsoft.com), you can use one of the following parameter types:

    SqlClient supports populating table-valued parameters from DataTable, DbDataReader or IEnumerable \ SqlDataRecord objects. You must specify a type name for the table-valued parameter by using the TypeName property of a SqlParameter. The TypeName must match the name of a compatible type previously created on the server.

    Not included in the docs but important for high-performance apps, a sample using IEnumerable<SqlDataRecord> (.NET Core 3.1, async):

      using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(30));
      using SqlConnection connection = this.GetConnection();
      await connection.OpenAsync(timeout.Token);
    
      using SqlCommand command = connection.CreateCommand();
      command.CommandType = CommandType.StoredProcedure;
      command.CommandText = "Mycommand";
    
      IEnumerable<SqlDataRecord> records = // ...
    
      SqlParameter parameter = command.Parameters.Add("@MyObjects", SqlDbType.Structured);
      parameter.TypeName = "MyCustomTableType";
      parameter.Value = records;
    
      await command.ExecuteNonQueryAsync(timeout.Token);
    

    Example using a DataTable:

      // Create a DataTable with the modified rows.  
      DataTable addedCategories = CategoriesDataTable.GetChanges(DataRowState.Added);  
    
      // Configure the SqlCommand and SqlParameter.  
      SqlCommand insertCommand = new SqlCommand("usp_InsertCategories", connection);  
      insertCommand.CommandType = CommandType.StoredProcedure;  
      SqlParameter tvpParam = insertCommand.Parameters.AddWithValue("@tvpNewCategories", addedCategories);  
      tvpParam.SqlDbType = SqlDbType.Structured;  
    
      // Execute the command.  
      insertCommand.ExecuteNonQuery(); 
    

    Example using DbDataReader:

     // Assumes connection is an open SqlConnection.  
     // Retrieve data from Oracle.  
     OracleCommand selectCommand = new OracleCommand(  
         "Select CategoryID, CategoryName FROM Categories;",  
         oracleConnection);  
     OracleDataReader oracleReader = selectCommand.ExecuteReader(  
         CommandBehavior.CloseConnection);  
    
      // Configure the SqlCommand and table-valued parameter.  
      SqlCommand insertCommand = new SqlCommand(  
          "usp_InsertCategories", connection);  
      insertCommand.CommandType = CommandType.StoredProcedure;  
      SqlParameter tvpParam =  
          insertCommand.Parameters.AddWithValue(  
          "@tvpNewCategories", oracleReader);  
      tvpParam.SqlDbType = SqlDbType.Structured;  
    
      // Execute the command.  
      insertCommand.ExecuteNonQuery(); 
    
    0 讨论(0)
  • 2020-11-28 12:15

    You can pass the parameter as a DataTable, IEnumerable<SqlDataRecord>, or DbDataReader.

    0 讨论(0)
  • 2020-11-28 12:22

    The following example illustrates using either a DataTable or an IEnumerable<SqlDataRecord>:

    SQL Code

    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

    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;
        }
    }
    
    0 讨论(0)
提交回复
热议问题