zoukankan      html  css  js  c++  java
  • 利用SqlBulkCopy实现网上答题系统

    利用SqlBulkCopy实现网上答题系统

    摘 要 本文利用.Net 2.0引入的SqlBulkCopy新类结合SQL Server2005实现网上答题系统。介绍一种把其它数据源的数据批量加载到SQL Server表的高效方法,并确保其插入数据的完整性,一致性。

    关键字 .Net 2.0C#SqlBulkCopy,批量加载

     

    一、前言

    问卷调查是获取用户信息最有效途径之一,不管是企业单位,还是政府部门都广泛采用。

    利用网上这种途径来收集信息,可以节省大量的人力和物力。而同样有奖问题、网上考试也被各个企业单位广泛应用。其实现方式都可以通过网上答题系统来实现。  

    网上答题的题型主要有单项选择题,多项选择题和判断题。以往网上答题系统的实现方式是程序收集用户回答的答题信息,通过编写事务,把答题信息逐条的写入数据库。这样主要有两个问题。一是需要开发人员自己写事务来处理把答题信息插入数据库。如果处理不好会使收集的答题信息不完整,给开发人员带来不少的麻烦和开发难度。另外就是程序效率比较低下,特别是在题量比较大的情况下。通过.Net 2.0引入的SqlBulkCopy新类可以有效的解决这些问题。

    本文结合笔者的开发和应用实践,详细介绍利用SqlBulkCopy实现网上答题系统的原理和关键步骤。

    二、SqlBulkCopy介绍

    SqlBulkCopy.NET Framework 2.0新增的类,位于命名空间System.Data.SqlClient下,主要提供把其它数据源的数据有效批量的加载到SQL Server表中的功能。类似与 Microsoft SQL Server 包中名为 bcp 的命令行应用程序。但是使用 SqlBulkCopy 类可以编写托管代码解决方案,性能上优于bcp命令行应用程序,更优于如Insert方式向SQL Server表加载大量数据。SqlBulkCopy可以应用到大批量数据的转移上,而不管数据源是什么。

    三、数据库设计

    1、数据表设计

    打开SQL Server2005,建立数据表tUsertAnswer,分别是用户信息表和答题表。具体数据库关系和字段如图1所示:


    1 数据表及关系图

    具体思路是:用户根据答题内容回答完题,并填写完用户的个人信息。程序首先收集这些数据,并向用户信息表插入用户信息,返回该用户的编号(即UserID)。再根据用户编号生成内存表DataTable,利用SqlBulkCopy把内存表中数据批量的插入答题表。由数据提交的情况向用户返回成功或失败的消息。

    2、存储过程设计

    新增一个存储过程AddNewUser,完成根据姓名、电话和身份证号向用户信息表插入用户信息,返回自增量字段生成的用户ID号功能,具体代码如下:

    CREATE PROCEDURE [dbo].[AddNewUser]

    @fUserName varchar(50),

    @fPhone varchar(100),

    @fIDCard varchar(50),

    @fUserID int output—传出参数

    AS

    begin tran

    SET NOCOUNT ON;

    insert into tUser (fUserName,fPhone,fIDCard)values(@fUserName,@fPhone,@fIDCard);

    set @fUserID=(SELECT @@identity);--返回用户ID

    if @@error!=0   rollback

        else    commit

    四、程序实现

       根据图2制作网页,其中单项选择题和判断题使用RadioButtonList服务器控件,多项选择题使用CheckBoxList服务器控件。设置好各服务器控件的属性,题所使用控件的命名采用“题型+序号”的命名方式,如选择题第一题命名为:a1


    2 程序界面图

    随后添加“提交答卷”按钮的单击事件,核心代码如下:

    protected void Button1_Click(object sender, EventArgs e)

            {

                //构建内存答题表dt,用来存放获取的答题信息

                DataTable dt = new DataTable();

                dt.Columns.Add("UserID", typeof(int));

                dt.Columns.Add("QuestionID", typeof(int));

                dt.Columns.Add("Answer", typeof(string));

                int UserID = 0;

                int QuestionID = 0;

                string Answer = string.Empty;

                //采用遍历获取数据

                foreach (Control ctl in form1.Controls)

                {

                    //获取单选题、判断题的答题数据

                    if (ctl is RadioButtonList)

                    {

                        QuestionID = int.Parse(ctl.ID.Substring(1, ctl.ID.Length - 1));

                        Answer = ((RadioButtonList)ctl).SelectedValue;

              //把数据添加到构建的内存答题表dt

                        AddRow(ref dt, UserID, QuestionID, Answer);

                    }

                    if (ctl is CheckBoxList)

                    {

                        //获取多选题的答题数据

                        Answer = string.Empty;

                        QuestionID = int.Parse(ctl.ID.Substring(1, ctl.ID.Length - 1));

                        CheckBoxList cbl = (CheckBoxList)ctl;

                        for (int i = 0; i < cbl.Items.Count; i++)

                        {

                            if (cbl.Items[i].Selected)

                            {

                                Answer += cbl.Items[i].Value;

                            }

                        }

                        AddRow(ref dt, UserID, QuestionID, Answer);

                    }

                }

                //获取用户信息

                string UserName = txtUserName.Text;

                string Phone = txtPhone.Text;

                string IDCard = txtIDCard.Text;

                try

                {               

                    string spName = "AddNewUser";

            //省略部分是根据存储过程得到UserID

                       ……

                       //更新内存答题表dt信息

                    foreach (DataRow dr in dt.Rows)

                    {

                        dr["UserID"] = UserID;

                    }

            //通过SqlBulkCopy把内存答题表数据更新到Sql Server数据库中

                    SqlBulkCopyData(dt);

                    Label1.Text="提交答卷成功! ";

                }

                catch

                {

                   Label1.Text="系统错误,请和系统管理员联系! ";

                }

            }

    程序先在内存中构建用来存放答题信息的答题表dt,随后采用遍历的方式获取答题的数据,并通过AddRow()函数把获取的数据保存在构建的dt表中。AddRow()函数代码如下:

    protected void AddRow(ref DataTable dt, int UserID, int QuestionID, string Answer)

           {

              DataRow dr = dt.NewRow();

              dr["UserID"] = UserID;

              dr["QuestionID"] = QuestionID;

              dr["Answer"] = Answer;

              dt.Rows.Add(dr);

            }

    根据获取的答题数据调用存储过程AddNewUser保存用户信息,返回用户编号。更新答题表信息,通过SqlBulkCopy把答题表的数据批量加载到SQL Server数据库中,加载数据的代码如下:

            protected void SqlBulkCopyData(DataTable dt)

            {

                //使用SqlBulkCopy把内存表DataTable里的数据插入答卷数据表

                SqlBulkCopy bcp = new SqlBulkCopy(connectionString);

          //指定目标数据库的表名

                bcp.DestinationTableName = "tAnswer";

                //建立数据源表字段和目标表中的列之间的映射

                SqlBulkCopyColumnMapping MapUserID = new SqlBulkCopyColumnMapping();

                MapUserID.DestinationColumn = "fUserID";

                MapUserID.SourceColumn = "UserID";

                bcp.ColumnMappings.Add(MapUserID);

                SqlBulkCopyColumnMapping MapQID = new SqlBulkCopyColumnMapping();

                MapQID.DestinationColumn = "fQuestionID";

                MapQID.SourceColumn = "QuestionID";

                bcp.ColumnMappings.Add(MapQID);

                SqlBulkCopyColumnMapping MapAnswer = new SqlBulkCopyColumnMapping();

                MapAnswer.DestinationColumn = "fAnswer";

                MapAnswer.SourceColumn = "Answer";

                bcp.ColumnMappings.Add(MapAnswer);

                //写入数据库表

                bcp.WriteToServer(dt);

                bcp.Close();

            }

    SqlBulkCopy 包含一个方法 WriteToServer,它用来从数据的源复制数据到数据的目的地。WriteToServer方法可以处理的数据类型有DataRow[]数组、DataTable DataReader。根据实际情况,我们选用DataTable。程序先根据连接目标数据库的连接字符串生成SqlBulkCopy 实例,并指定DestinationTableName属性,也就是目标数据库的表名。再通过SqlBulkCopyColumnMapping类,设置数据源字段到目标数据表字段的映射。也就是说如果目标数据和源数据的列名不同时,可以用这个类进行映射。最后通过WriteToServer把数据加载到数据库中。

    如果目标表中的数据量比较大,需要设置SqlBulkCopyBatchSize,使加载数据分批进行,在每一批次结束时,就将该批次中的行发送到数据库。根据程序运行情况,给用户返回答卷提交结果。

    五、结束语

      以上程序在VS2005(C#)SQL Server 2005, Windows 2003 SP1环境下编译调试通过。利用.NET 2.0引入的SqlBulkCopy新类,实现对SQL Server数据库的批量加载。这种技术在实际开发项目网上答题系统中得到了充分利用。本系统根据各自的需求,增加答题内容,不用修改任何程序就可以用到实际的业务中。

    参考文献

    1MSDN文档

  • 相关阅读:
    又玩起了“数独”
    WebService应用:音乐站图片上传
    大家都来DIY自己的Blog啦
    CSS导圆角,不过这个代码没有怎么看懂,与一般的HTML是不同
    网站PR值
    CommunityServer2.0何去何从?
    网络最经典命令行
    炎热八月,小心"落雪"
    Topology activation failed. Each partition must have at least one index component from the previous topology in the new topology, in the same host.
    SharePoint 2013服务器场设计的一些链接
  • 原文地址:https://www.cnblogs.com/13590/p/807065.html
Copyright © 2011-2022 走看看