65.9K
CodeProject 正在变化。 阅读更多。
Home

SQL Server 2008的表值参数

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.14/5 (3投票s)

2011 年 11 月 16 日

CPOL

2分钟阅读

viewsIcon

26625

downloadIcon

379

如何创建通用的存储过程来将数据插入到任何表中。

引言

表值参数 (TVP) 是 SqlServer 最有用的功能之一。我们可以创建一个用户定义的 TVP,并将其作为参数在任何存储过程中使用。当我们在大型项目上工作时,我们需要创建许多存储过程来插入数据,有时一个表需要多个存储过程。在这里,我尝试创建一个通用的存储过程,用于将数据插入到具有 n 列的任何表中。

背景 

请了解集合的使用,以便更好地理解本文。
 

使用代码 

要使用此功能,我们需要遵循以下步骤。
 

1- 我们需要创建一个表来插入数据。

/* Create table Emp */
   create table Emp(
        EmpCode int,
	EmpName varchar(20)
)
Go

 2- 使用以下脚本创建一个用户定义的表值参数。

/* Create the User defined Table type */
CREATE TYPE [dbo].[pTableData] AS TABLE(
      [ColName] [varchar](50) NULL,
      [ColValue] [varchar](100) NULL
)

GO
 

执行以上脚本后,应该在 Programmability>Types>User-Defined Table Type 中显示一个新的用户定义对象,如下屏幕所示。

 

 3- 现在我们正在创建一个通用的存储过程,用于使用我们在第二点中创建的用户定义表类型来插入数据。

/* Create procedure to insert data in any table with n number of columns */
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)
 

4- 为了在后端测试该存储过程,我们需要使用以下脚本- 

/*To test the procedure at back end use 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', @par
 

好的,我们已经完成了数据库的工作,现在是时候了解如何从 dotnet 客户端应用程序调用此存储过程了。我们需要完成以下步骤来调用此存储过程-

1- 首先,我们需要设计一个包含两个文本框和一个按钮的网页,如下屏幕所示-

 

2 - 上述网页的代码文件应包含以下代码 -

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");
    }
   
}
   

 

2- 在业务逻辑文件中,我正在创建一个名为 Emp 的类,其中包含所有属性和关于 Emp 类的业务逻辑。 

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;

/// <summary>
/// Summary description for CategoryMaster
/// </summary>
/// 
/// 
namespace LoopBreak
{
    public class Emp
    {
        //Object declaration section
        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);
            
        }
    }
}

我们正在创建 DataCollection 类的对象,该类是用户数据的集合,就像 Ado.Net 中的 DataTable 一样。我们也可以在这里使用 DataTable 来执行相同的任务来存储所有要插入的行。我们已经在 DataCollection 类中实现了 List 和 IEnumerable 类型,以便为从类中迭代数据添加额外的功能。

    /// <summary>
    /// DataCollection class stores the data to insert.
    /// </summary>
    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;
            }
        }

       
    } 

 DataDetail 类用于存储有关插入数据的的信息。表名、数据集合和一种将数据添加到数据集合的方法。 

 

    /// <summary>
    /// DataDetails class contains the inserted data details. 
    /// </summary>
    
    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);
        }
    }

 数据访问层包含以下代码,用于使用该过程插入数据-

 

    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;
/// <summary>
/// Summary description for DAL
/// </summary>
/// 
namespace LoopBreak
{
    public class DAL
    {
        public DAL() { }

        /// <summary>
        /// Returns the type of data provider that the application is using. The application will read from it's config file in the Provider element
        /// of the AppSettings node.
        /// </summary>
        /// <returns></returns>
        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();
            }

        }
    }

    /// <summary>
    /// DataDetails class contains the inserted data details. 
    /// </summary>
    
    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);
        }
    }

    /// <summary>
    /// DataRow class used to add a new row in DataCollection class.
    /// </summary>
    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; }
        }
    }

    /// <summary>
    /// DataCollection class stores the data to insert.
    /// </summary>
    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
}

 我们正在使用 DBInsert 类的 InsertData 方法将数据插入到任何表中。这将插入到具有 n 列的任何表中的数据。

 

希望这有助于减少代码,并为修改代码提供更大的灵活性。

谢谢。

Rahul

值得关注的点  

在编写代码时,您是否学到了任何有趣/有趣/令人恼火的东西? 您是否做了任何特别聪明或疯狂或异想天开的事情? 

历史 

 

© . All rights reserved.