5

I am trying to figure out if there is a way to perform a multiple values insert in Sql Server while using parameters, to be precise, having a command like this:

com = new SqlCommand("insert into myTable values (@recID,@tagID)", con);
com.Parameters.Add("@recID", SqlDbType.Int).Value = recID;
com.Parameters.Add("@tagID", SqlDbType.Int).Value = tagID;
com.ExecuteNonQuery();

Is there a way to perform a multiple values single insert with parameters taking into account that parameters may be different for each value? (Example: tagID may be always different)

I have been searching in Internet but no luck so far, thanks in advance, greetings.

Sosian
  • 622
  • 11
  • 28
JCO9
  • 960
  • 1
  • 15
  • 24

2 Answers2

7

You can use a table valued parameters : How to pass table value parameters to stored procedure from .net code

First, create the type, in SQL Server :

CREATE TYPE [dbo].[myTvpType] AS TABLE 
(
    [RecordID] int,
    [TagID] int
)

And the C# code to insert your data :

internal void InsertData(SqlConnection connection, Dictionary<int, int> valuesToInsert)
{
    using (DataTable myTvpTable = CreateDataTable(valuesToInsert))
    using (SqlCommand cmd = connection.CreateCommand())
    {
        cmd.CommandText = "INSERT INTO myTable SELECT RecordID, TagID FROM @myValues";
        cmd.CommandType = CommandType.Text;

        SqlParameter parameter = cmd.Parameters.AddWithValue("@myValues", myTvpTable);
        parameter.SqlDbType = SqlDbType.Structured;

        cmd.ExecuteNonQuery();
    }
}

private DataTable CreateDataTable(Dictionary<int, int> valuesToInsert)
{
    // Initialize the DataTable
    DataTable myTvpTable = new DataTable();
    myTvpTable.Columns.Add("RecordID", typeof(int));
    myTvpTable.Columns.Add("TagID", typeof(int));

    // Populate DataTable with data
    foreach(key in valuesToInsert.Key)
    {
        DataRow row = myTvpTable.NewRow();
        row["RecordID"] = valuesToInsert[key];
        row["TagID"] = key;
    }
}
Community
  • 1
  • 1
Rom Eh
  • 1,981
  • 1
  • 16
  • 33
0

You can do this by sending your data as an xml string and convert in into table in a stored procedure in sql. For example: suppose I am sending multiple rows to add/update in an sql table then here are the steps:

  1. Convert your class or list of class into an xml string using following method:

    public static string SerializeObjectToXmlString(object value)
    
              {
              var emptyNamepsaces = new XmlSerializerNamespaces(new[] { 
                                        XmlQualifiedName.Empty });
    
        var serializer = new XmlSerializer(value.GetType());
        var settings = new XmlWriterSettings();
        settings.Indent = true;
        settings.OmitXmlDeclaration = true;
    
        using (var stream = new StringWriter())
        using (var writer = XmlWriter.Create(stream, settings))
        {
            serializer.Serialize(writer, value, emptyNamepsaces);
            return stream.ToString();
        }
    }
    
  2. Now while sending data to the database convert your class object into xml string (Here I am using entity framework in my code, you can do this without using it as well):

    bool AddUpdateData(List<MyClass> data)
    {
        bool returnResult = false;
        string datatXml = Helper.SerializeObjectToXmlString(data);
        var sqlparam = new List<SqlParameter>()
                     {
       new SqlParameter() { ParameterName = "dataXml", Value = datatXml}
    
                     };
        var result = this.myEntity.Repository<SQL_StoredProc_ComplexType>().ExecuteStoredProc("SQL_StoredProc", sqlparam);
        if (result != null && result.Count() > 0)
        {
            returnResult = result[0].Status == 1 ? true : false;
        }
        return returnResult;
    }
    
  3. Now your SQL Code:

3.1 Declare a table variable:

DECLARE @tableVariableName TABLE
(
    ID INT, Name VARCHAR(20)
)

3.2 Insert Your xml string into Table variable

INSERT INTO @tableVariableName
SELECT 
    Finaldata.R.value ('(ID/text())[1]', 'INT') AS ID, 
    Finaldata.R.value ('(Name/text())[1]', 'VARCHAR(20)') AS Name
FROM @MyInputXmlString.nodes ('//ArrayMyClass/MyClass') AS Finaldata (R)

3.3 Finally insert this table value into your sql table

INSERT INTO MyTable (ID, Name)                  
SELECT ID, Name          
FROM @tableVariableName

This will save your effort of hitting database again and again using a for loop.

Hope it will help you

Pranav Mishra
  • 456
  • 2
  • 7
  • 14
  • 1
    Whilst this may theoretically answer the question, [it would be preferable](//meta.stackoverflow.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – David Glickman May 24 '17 at 08:40