Introduction
Table Values Parameter (TVP) is one of the most useful
features of SqlServer. We can create a user defined TVP and can use this as
parameter in any procedure. When we worked on the large projects we need to
create number of procedures to insert the data means one procedure for each
table some time more than one. Here I am trying to create a single procedure to
insert the data in any table with n number of columns.
Background
Have a look on collections to use and understand this article.
Using the code
To use this we need to follow the following steps.
1- We need to create a table to insert the data.
create table Emp(
EmpCode int,
EmpName varchar(20)
)
GoColourised in 1ms
2- Use following script to create a user defined Table Valued Parameter.
CREATE TYPE [dbo].[pTableData] AS TABLE(
[ColName] [varchar](50) NULL,
[ColValue] [varchar](100) NULL
)
GOColourised in 3ms
After execution the above script a new user defined object should be displayed in Programmability>Types>User-Defined Table Type as in the following screen.
3- Now we are creating a common procedure to insert the data using the User-Defined Table Types which we have created in the second point.
Create procedure LB_SP_InsertData
(
@pTableName varchar(100), --Table Name
@pData pTableData readonly --Table data
)
as
Declare @SqlText as varchar(5000)
SET @SqlText='insert into '+@pTableName+'('
select @SqlText += ColName+',' from @pData
SET @SqlText=SUBSTRING(@SqlText,0,LEN(@SqlText))
SET @SqlText+=')values('
select @SqlText +=''''+ColValue+''''+',' from @pData
SET @SqlText=SUBSTRING(@SqlText,0,LEN(@SqlText))
SET @SqlText+=')'
PRINT (@SqlText)
Exec(@SqlText)Colourised in 18ms
4- To test the procedure at back end we need to use the following script-
declare @par as pTableData
insert into @par values('EmpCode','50')
insert into @par values('EmpName','Rahul Pratap Singh')
--select * from @par
Exec LB_SP_InsertData 'Emp', @parColourised in 5ms
Ok we have done with database, its time to understand how to
call this procedure from dotnet client application, we need to complete the
following steps to call this procedure-
1- First of all we need to design a web page with two text box and a button as in the following screen-
2 - the code file of the above web page should contains the following code -
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using LoopBreak;
using System.Data;
public partial class UserRegistration : System.Web.UI.Page
{
Emp objUser = new Emp();
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
objUser.EmpCode = Convert.ToInt32(txtEmpCode.Text);
objUser.EmpName = txtEmpName.Text;
objUser.RegisterUser();
Response.Redirect("Success.aspx");
}
}Colourised in 16ms
2- In business logic file, i am creating a class name Emp which contains all the properties and business logic regarding the Emp class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using Microsoft.SqlServer.Server;
using System.Collections;
namespace LoopBreak
{
public class Emp
{
DataCollection objUserDataCollection = new DataCollection();
DataDetail objDataDetails = new DataDetail();
#region "Property Declaration"
public int EmpCode { get; set; }
public string EmpName { get; set; }
#endregion
public void RegisterUser()
{
objDataDetails._DataCollection = this.objUserDataCollection;
objDataDetails._strTableName = clsConstant.cnsttblUser_Master;
objDataDetails.AddDataToDataCollection("EmpCode", this.EmpCode.ToString());
objDataDetails.AddDataToDataCollection("EmpName", this.EmpName);
DBInsert.InsertData(objDataDetails);
}
}
}Colourised in 26ms
We are creating the object of DataCollection class which is the collection of user data just like as DataTable in Ado.Net, we can also use DataTable here for the same task to store all the rows to insert. We have implemented the List and IEnumerable type in the DataCollection class to adding extra functionality to iterate the data from the class.
public class DataCollection : List<DataRow>, IEnumerable<SqlDataRecord>
{
IEnumerator<SqlDataRecord> IEnumerable<SqlDataRecord>.GetEnumerator()
{
var sdr = new SqlDataRecord(
new SqlMetaData("ColName", SqlDbType.VarChar, 50),
new SqlMetaData("ColValue", SqlDbType.VarChar, 5000)
);
foreach (DataRow objUserData in this)
{
sdr.SetString(0, objUserData.StrColName);
sdr.SetString(1, objUserData.StrColValue);
yield return sdr;
}
}
}
Colourised in 15ms
The DataDetail class used to store the information about inserted data.Table name data collection and a method to add the data in data collection.
public class DataDetail
{
string strTableName;
public string _strTableName
{
get { return strTableName; }
set { strTableName = value; }
}
private DataCollection DataCollection;
public DataCollection _DataCollection
{
get { return DataCollection; }
set { DataCollection = value; }
}
public void AddDataToDataCollection(string strColName, string strColValue)
{
DataRow objDataRow = new DataRow();
objDataRow.StrColName = strColName;
objDataRow.StrColValue = strColValue;
DataCollection.Add(objDataRow);
}
}
Colourised in 15ms
The Data Access Layer contains the following code to insert the data using the procedure-
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
using Microsoft.SqlServer.Server;
namespace LoopBreak
{
public class DAL
{
public DAL() { }
public static string GetProviders()
{
string provider = ConfigurationSettings.AppSettings["conStr"];
return provider;
}
}
#region "Procedure to insert the data"
public class DBInsert
{
public static void InsertData(DataDetail pUserDetails)
{
SqlConnection objSqlConnection = null;
SqlCommand objSQLComman=null;
try
{
objSQLComman = new SqlCommand(clsConstant.cnstLB_SP_InsertData);
objSQLComman.CommandType = CommandType.StoredProcedure;
objSqlConnection = new SqlConnection(DAL.GetProviders());
objSQLComman.Connection = objSqlConnection;
SqlParameter parTableName = new SqlParameter("@pTableName", SqlDbType.VarChar, 100);
parTableName.Value = pUserDetails._strTableName;
objSQLComman.Parameters.Add(parTableName);
SqlParameter parData = new SqlParameter("@pData", SqlDbType.Structured);
parData.TypeName = "dbo.pTableData";
parData.Value = pUserDetails._DataCollection;
objSQLComman.Parameters.Add(parData);
objSqlConnection.Open();
objSQLComman.ExecuteNonQuery();
}
catch (Exception Ex)
{
throw Ex;
}
finally
{
if (objSQLComman != null)
{
objSQLComman.Dispose();
}
if (objSqlConnection .State == ConnectionState.Open)
{
objSqlConnection.Close();
}
objSqlConnection.Close();
}
}
}
public class DataDetail
{
string strTableName;
public string _strTableName
{
get { return strTableName; }
set { strTableName = value; }
}
private DataCollection DataCollection;
public DataCollection _DataCollection
{
get { return DataCollection; }
set { DataCollection = value; }
}
public void AddDataToDataCollection(string strColName, string strColValue)
{
DataRow objDataRow = new DataRow();
objDataRow.StrColName = strColName;
objDataRow.StrColValue = strColValue;
DataCollection.Add(objDataRow);
}
}
public class DataRow
{
string strColName;
public string StrColName
{
get { return strColName; }
set { strColName = value; }
}
string strColValue;
public string StrColValue
{
get { return strColValue; }
set { strColValue = value; }
}
}
public class DataCollection : List<DataRow>, IEnumerable<SqlDataRecord>
{
IEnumerator<SqlDataRecord> IEnumerable<SqlDataRecord>.GetEnumerator()
{
var sdr = new SqlDataRecord(
new SqlMetaData("ColName", SqlDbType.VarChar, 50),
new SqlMetaData("ColValue", SqlDbType.VarChar, 5000)
);
foreach (DataRow objUserData in this)
{
sdr.SetString(0, objUserData.StrColName);
sdr.SetString(1, objUserData.StrColValue);
yield return sdr;
}
}
}
#endregion
}Colourised in 100ms
We are using the InsertData methos of DBInsert class to insert the data in any table. this will insert the data in any table of n numer of columns.
Hope this will help to reduce the code and will give the more flexiblity to modify the code.
Thanks.
Rahul
Points of Interest
Did you learn anything interesting/fun/annoying while writing
the code? Did you do anything particularly clever or wild or zany?
History