利用SqlBulkCopy多次导入sql server2000,但发生内容重复,求解决办法!

时间:2022-04-02 06:37:10
本人创建了一个程序,大致框架如下:

触发button事件--->导入一张excel表,最终将excel表的数据导入sql server 2000

button事件大略如下:

{

  OpenFileDialog openFile1 = new OpenFileDialog();   //要求用户导入目标Excel表

  new DataSet();  

  new DataTable();

{

     //  将Excel表元数据导入DataTable,生成多条DataRow

}

  using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn))    //将DataTable批量导入sql server 2000

  {

   bulkCopy.WriteToServer(DataTable);

   }

}

-----------------------------------------

当点第一次button,导入表1之后,查询sql server,发现有一张表1的内容;

但是,点第二次button,导入表2,再次查询sql server,却发现内容为:

表1+表1+表2

也就是说重复了表1的内容。跟踪SqlBulkCopy的运行次数:总共只为2,不是3。

我试过在SqlBulkCopy之后写Dataset.Clear()和DataTable.Clear()也无济于事。

请问问题出现在哪?解决办法是什么呢?

9 个解决方案

#1


补充一下,数据库中对应的表没有主键,只有两个外键约束

#2


LZ 你代码最好贴全
从问题来看

你最好跟一下 第二次BUTTON 时的 DATATABLE的内容。

估计没错的话,应该是第一个BUTTON后,EXCEL 没有释放~

然后第二BUTTON时 EXCEL 的SHEET发生合并了

#3


代码比较长:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.Office.Interop.Excel;
using System.Data.SqlClient;

namespace IOdatabase
{
    public partial class Form1 : Form
    {
        public Sheets sheets;
        public Worksheet datasheet;
        public Range range;   //数据表中对应范围的数据
        public System.Array Cellarray;   //数据表中对应范围的数据转换为数组形式
        public SqlConnection conn;

        public Form1()
        {
            InitializeComponent();
            this.textBox1.ReadOnly = true;   //设置TextBox为只读
            this.textBox1.BackColor = Color.White;   //设置TextBox的背景色为白色
            this.dataGridView1.ReadOnly = true;   //设置DataGridView为只读
        }

        private void button1_Click(object sender, EventArgs e)   //按钮:“导入表”
        {
            this.textBox1.Clear();
            OpenFileDialog openFile1 = new OpenFileDialog();   //动态添加OpenFileDialog控件,用于弹出一个窗口提示用户打开文件
            openFile1.Filter = "Microsoft Excel 工作表|*.xls";
            if (openFile1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                int count = 0;
                string OpenFilePath = openFile1.FileName;
                Microsoft.Office.Interop.Excel.ApplicationClass app = new ApplicationClass();
                app.Visible = false;
                WorkbookClass Workbook = (WorkbookClass)app.Workbooks.Open(OpenFilePath);//打开对应路径的Excel
                object missing = Type.Missing;
                sheets = Workbook.Worksheets;
                this.textBox1.Text += "正在解析..." + Environment.NewLine;

                //判断导入的表是否是完整sheet的表
                foreach (Worksheet sheet in sheets)
                {
                    if (sheet.Name == "寿险公司" || sheet.Name == "财产公司" || sheet.Name == "明细表" || sheet.Name == "赔款")  
                    {
                        count++;
                    }
                }
                if (count > 0 && count < 4)
                {
                    this.textBox1.Text += "导入的表,其中包含的sheet不完整,请重新导入!";
                    return;
                }
                else if (count == 0)
                {
                    this.textBox1.Text += "导入了格式完全错误的表,请重新导入!";
                    return;
                }
                else
                {
                    this.textBox1.Text += "表的格式完全正确,正在导入数据库!"+Environment.NewLine;
                }
                //   解析出表的“年”、“月”
                datasheet = null;
                foreach (Worksheet sheet in sheets)
                {
                    if (sheet.Name == "寿险公司")   //读取“寿险公司”的sheet;
                    {
                        datasheet = sheet;
                        break;
                    }
                }
                range = datasheet.get_Range("G2");
                string data = (System.String)range.Value;
                string[] dataArray = data.Split(new char[2] { '年', '月' });   //dataArray[0]为年份,dataArray[1]为月份
                                                                            /*
                                                                            要导入填充函数的三个参量:sheets(完整的表)、
                                                                            dataArray[0](年份)、dataArray[1](月份)
                                                                            */
                //---------------导入填充函数---------------//
                LoadSheetsFunction(Convert.ToInt32(dataArray[0]), Convert.ToInt32(dataArray[1]));

                //-------------------回收Excel进程-------------------//
                Workbook.Close();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(Workbook);
                Workbook = null;
                app.Quit();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
                app = null;
                System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets);
                sheets = null;
                System.Runtime.InteropServices.Marshal.ReleaseComObject(datasheet);
                datasheet = null;
                GC.Collect();
            }
        }
        void LoadSheetsFunction(int year, int month)   //填充函数
        {
            string connString = @"
            server = (local);
            integrated security = true;
            database = ExcelDatabase
         ";   //   连接数据库的字符串

            using (conn = new SqlConnection(connString))
            {
                conn.Open();
                LoadLifeInsuranceCompany(year, month);   //填充“寿险公司”

            }
        }
        void LoadLifeInsuranceCompany(int year, int month)   //填充“寿险公司”的函数
        {
             foreach (Worksheet sheet in sheets)
            {
                if (sheet.Name == "寿险公司")   //读取“寿险公司”的sheet;
                {
                    datasheet = sheet;
                }
            }
            
            SqlCommand Newcmd = new SqlCommand("select * from LifeInsuranceCompany where (year=" + year.ToString() + ")" + "and (month=" + month.ToString() + ")", conn);
            SqlDataReader rdr = Newcmd.ExecuteReader();
            if (!rdr.HasRows)
                        {
                            rdr.Close();

                            string sql = @"select * from LifeInsuranceCompany";
                            SqlDataAdapter da = new SqlDataAdapter(sql, conn);
                            DataSet ds = new DataSet();
                            da.Fill(ds, "LifeInsuranceCompany");
                            System.Data.DataTable dt = ds.Tables["LifeInsuranceCompany"];

                            int[] Rowarray = new int[6] { 13, 21, 29, 37, 45, 53 };

                            for (int CompanyID = 1; CompanyID <= 6; CompanyID++)   //   填充DataTable
                            {
                                range = datasheet.get_Range("D" + Rowarray[CompanyID - 1].ToString(), "K" + (Rowarray[CompanyID - 1]+5).ToString());
                                Cellarray = (System.Array)range.Value;
                                for (int InsuranceID = 1; InsuranceID <= 5; InsuranceID++)
                                {
                                    DataRow newRow = dt.NewRow();
                                    newRow["year"] = year;
                                    newRow["month"] = month;
                                    newRow["CompanyID"] = CompanyID;
                                    newRow["InsuranceID"] = InsuranceID;
                                    newRow["NewInsurancePremium"] = (Cellarray.GetValue(InsuranceID, 1)!= null ? Cellarray.GetValue(InsuranceID,1) : DBNull.Value);
                                    newRow["RenewalPremium"] = (Cellarray.GetValue(InsuranceID, 3) != null ? Cellarray.GetValue(InsuranceID, 3) : DBNull.Value);
                                    newRow["ExpenditureAndPayment"] = (Cellarray.GetValue(InsuranceID, 5) != null ? Cellarray.GetValue(InsuranceID, 5) : DBNull.Value);
                                    newRow["GrossPremiumIncome"] = (Cellarray.GetValue(InsuranceID, 7) != null ? Cellarray.GetValue(InsuranceID, 7) : DBNull.Value);
                                    dt.Rows.Add(newRow);
                                }
                            }
                using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn))   //用SqlBulkCopy将DataTable的表批量导入到数据源
                            {
                                bulkCopy.DestinationTableName =
                                "LifeInsuranceCompany";
                                try
                                {
                                    // Write from the source to the destination.
                                    bulkCopy.WriteToServer(dt);
                                }
                                catch (Exception ex)
                                {
                                    this.textBox1.Clear();
                                    this.textBox1.Text+="数据导入失败!"+Environment.NewLine +ex;
                                }
                            }
            }
            else
            {
                this.textBox1.Clear();
                this.textBox1.Text += "寿险公司" + year.ToString() + "年" + month.ToString() + "月的表已经存在,不需要再次导入!";
                rdr.Close();
            }
        
        }
        
    }
}
       

#4


发现一个现象,就是第一次打开的Excel表,在程序关闭前一直驻留在内存,而第二次以上打开的表调用完成后会自动回收。

#5


datatable结果也是
表1+表1+表2

#6


LZ~~~阅读你的代码够费劲-_-

基本把你的意图理解为:

1读取EXCEL
2验证EXCEL数据
3从EXCEL获取 年,月属性
4根据年月属性从数据库中获取指定数据
5数据拼接成新的DATATABLE
6数据入库


目前看下来你的数据填充这块的业务逻辑有问题


    string sql = @"select * from LifeInsuranceCompany";

这里你获取了表中所有的数据
当第二次添加时,第一次数据也被取出,然后新的数据追加在了DT的后面。

当执行BULKCOPY时就等于多加了一次数据(1)

而数据库的数据变为 1+1+2了,如果第三次添加数据时则变为 1+1+2+1+1+2+3


既然你是新填数据,这里完全没有必要从原来的表中获取数据

                           

#7


我估计你这里

select * from LifeInsuranceCompany

的目的是想获取“LifeInsuranceCompany”这张表的结构(因为BULKCOPY这样要求,否则添加不了)

你完全可以通过这样的方法构建DATATABLE的结构


DataTable dt = new DataTable();
dt.Columns.Add("year", typeof(DateTime));

#8


另外给LZ一些额外的建议

1. 好好的提升一下自己代码编写的习惯。不是所有人都有耐心看完你这样的代码的...
2. 学习一下架构的知识(诸如三层架构等)。
3. 好的软件是能反复使用(或者说重用的)。

#9


引用 8 楼  的回复:
另外给LZ一些额外的建议

1. 好好的提升一下自己代码编写的习惯。不是所有人都有耐心看完你这样的代码的...
2. 学习一下架构的知识(诸如三层架构等)。
3. 好的软件是能反复使用(或者说重用的)。


谢谢您耐心的帮助!您指出的的"select * from LifeInsuranceCompany"的确是根源所在。

您说的“好好的提升一下自己代码编写的习惯”是指我目前的代码缺乏精简吗?

#1


补充一下,数据库中对应的表没有主键,只有两个外键约束

#2


LZ 你代码最好贴全
从问题来看

你最好跟一下 第二次BUTTON 时的 DATATABLE的内容。

估计没错的话,应该是第一个BUTTON后,EXCEL 没有释放~

然后第二BUTTON时 EXCEL 的SHEET发生合并了

#3


代码比较长:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.Office.Interop.Excel;
using System.Data.SqlClient;

namespace IOdatabase
{
    public partial class Form1 : Form
    {
        public Sheets sheets;
        public Worksheet datasheet;
        public Range range;   //数据表中对应范围的数据
        public System.Array Cellarray;   //数据表中对应范围的数据转换为数组形式
        public SqlConnection conn;

        public Form1()
        {
            InitializeComponent();
            this.textBox1.ReadOnly = true;   //设置TextBox为只读
            this.textBox1.BackColor = Color.White;   //设置TextBox的背景色为白色
            this.dataGridView1.ReadOnly = true;   //设置DataGridView为只读
        }

        private void button1_Click(object sender, EventArgs e)   //按钮:“导入表”
        {
            this.textBox1.Clear();
            OpenFileDialog openFile1 = new OpenFileDialog();   //动态添加OpenFileDialog控件,用于弹出一个窗口提示用户打开文件
            openFile1.Filter = "Microsoft Excel 工作表|*.xls";
            if (openFile1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                int count = 0;
                string OpenFilePath = openFile1.FileName;
                Microsoft.Office.Interop.Excel.ApplicationClass app = new ApplicationClass();
                app.Visible = false;
                WorkbookClass Workbook = (WorkbookClass)app.Workbooks.Open(OpenFilePath);//打开对应路径的Excel
                object missing = Type.Missing;
                sheets = Workbook.Worksheets;
                this.textBox1.Text += "正在解析..." + Environment.NewLine;

                //判断导入的表是否是完整sheet的表
                foreach (Worksheet sheet in sheets)
                {
                    if (sheet.Name == "寿险公司" || sheet.Name == "财产公司" || sheet.Name == "明细表" || sheet.Name == "赔款")  
                    {
                        count++;
                    }
                }
                if (count > 0 && count < 4)
                {
                    this.textBox1.Text += "导入的表,其中包含的sheet不完整,请重新导入!";
                    return;
                }
                else if (count == 0)
                {
                    this.textBox1.Text += "导入了格式完全错误的表,请重新导入!";
                    return;
                }
                else
                {
                    this.textBox1.Text += "表的格式完全正确,正在导入数据库!"+Environment.NewLine;
                }
                //   解析出表的“年”、“月”
                datasheet = null;
                foreach (Worksheet sheet in sheets)
                {
                    if (sheet.Name == "寿险公司")   //读取“寿险公司”的sheet;
                    {
                        datasheet = sheet;
                        break;
                    }
                }
                range = datasheet.get_Range("G2");
                string data = (System.String)range.Value;
                string[] dataArray = data.Split(new char[2] { '年', '月' });   //dataArray[0]为年份,dataArray[1]为月份
                                                                            /*
                                                                            要导入填充函数的三个参量:sheets(完整的表)、
                                                                            dataArray[0](年份)、dataArray[1](月份)
                                                                            */
                //---------------导入填充函数---------------//
                LoadSheetsFunction(Convert.ToInt32(dataArray[0]), Convert.ToInt32(dataArray[1]));

                //-------------------回收Excel进程-------------------//
                Workbook.Close();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(Workbook);
                Workbook = null;
                app.Quit();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
                app = null;
                System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets);
                sheets = null;
                System.Runtime.InteropServices.Marshal.ReleaseComObject(datasheet);
                datasheet = null;
                GC.Collect();
            }
        }
        void LoadSheetsFunction(int year, int month)   //填充函数
        {
            string connString = @"
            server = (local);
            integrated security = true;
            database = ExcelDatabase
         ";   //   连接数据库的字符串

            using (conn = new SqlConnection(connString))
            {
                conn.Open();
                LoadLifeInsuranceCompany(year, month);   //填充“寿险公司”

            }
        }
        void LoadLifeInsuranceCompany(int year, int month)   //填充“寿险公司”的函数
        {
             foreach (Worksheet sheet in sheets)
            {
                if (sheet.Name == "寿险公司")   //读取“寿险公司”的sheet;
                {
                    datasheet = sheet;
                }
            }
            
            SqlCommand Newcmd = new SqlCommand("select * from LifeInsuranceCompany where (year=" + year.ToString() + ")" + "and (month=" + month.ToString() + ")", conn);
            SqlDataReader rdr = Newcmd.ExecuteReader();
            if (!rdr.HasRows)
                        {
                            rdr.Close();

                            string sql = @"select * from LifeInsuranceCompany";
                            SqlDataAdapter da = new SqlDataAdapter(sql, conn);
                            DataSet ds = new DataSet();
                            da.Fill(ds, "LifeInsuranceCompany");
                            System.Data.DataTable dt = ds.Tables["LifeInsuranceCompany"];

                            int[] Rowarray = new int[6] { 13, 21, 29, 37, 45, 53 };

                            for (int CompanyID = 1; CompanyID <= 6; CompanyID++)   //   填充DataTable
                            {
                                range = datasheet.get_Range("D" + Rowarray[CompanyID - 1].ToString(), "K" + (Rowarray[CompanyID - 1]+5).ToString());
                                Cellarray = (System.Array)range.Value;
                                for (int InsuranceID = 1; InsuranceID <= 5; InsuranceID++)
                                {
                                    DataRow newRow = dt.NewRow();
                                    newRow["year"] = year;
                                    newRow["month"] = month;
                                    newRow["CompanyID"] = CompanyID;
                                    newRow["InsuranceID"] = InsuranceID;
                                    newRow["NewInsurancePremium"] = (Cellarray.GetValue(InsuranceID, 1)!= null ? Cellarray.GetValue(InsuranceID,1) : DBNull.Value);
                                    newRow["RenewalPremium"] = (Cellarray.GetValue(InsuranceID, 3) != null ? Cellarray.GetValue(InsuranceID, 3) : DBNull.Value);
                                    newRow["ExpenditureAndPayment"] = (Cellarray.GetValue(InsuranceID, 5) != null ? Cellarray.GetValue(InsuranceID, 5) : DBNull.Value);
                                    newRow["GrossPremiumIncome"] = (Cellarray.GetValue(InsuranceID, 7) != null ? Cellarray.GetValue(InsuranceID, 7) : DBNull.Value);
                                    dt.Rows.Add(newRow);
                                }
                            }
                using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn))   //用SqlBulkCopy将DataTable的表批量导入到数据源
                            {
                                bulkCopy.DestinationTableName =
                                "LifeInsuranceCompany";
                                try
                                {
                                    // Write from the source to the destination.
                                    bulkCopy.WriteToServer(dt);
                                }
                                catch (Exception ex)
                                {
                                    this.textBox1.Clear();
                                    this.textBox1.Text+="数据导入失败!"+Environment.NewLine +ex;
                                }
                            }
            }
            else
            {
                this.textBox1.Clear();
                this.textBox1.Text += "寿险公司" + year.ToString() + "年" + month.ToString() + "月的表已经存在,不需要再次导入!";
                rdr.Close();
            }
        
        }
        
    }
}
       

#4


发现一个现象,就是第一次打开的Excel表,在程序关闭前一直驻留在内存,而第二次以上打开的表调用完成后会自动回收。

#5


datatable结果也是
表1+表1+表2

#6


LZ~~~阅读你的代码够费劲-_-

基本把你的意图理解为:

1读取EXCEL
2验证EXCEL数据
3从EXCEL获取 年,月属性
4根据年月属性从数据库中获取指定数据
5数据拼接成新的DATATABLE
6数据入库


目前看下来你的数据填充这块的业务逻辑有问题


    string sql = @"select * from LifeInsuranceCompany";

这里你获取了表中所有的数据
当第二次添加时,第一次数据也被取出,然后新的数据追加在了DT的后面。

当执行BULKCOPY时就等于多加了一次数据(1)

而数据库的数据变为 1+1+2了,如果第三次添加数据时则变为 1+1+2+1+1+2+3


既然你是新填数据,这里完全没有必要从原来的表中获取数据

                           

#7


我估计你这里

select * from LifeInsuranceCompany

的目的是想获取“LifeInsuranceCompany”这张表的结构(因为BULKCOPY这样要求,否则添加不了)

你完全可以通过这样的方法构建DATATABLE的结构


DataTable dt = new DataTable();
dt.Columns.Add("year", typeof(DateTime));

#8


另外给LZ一些额外的建议

1. 好好的提升一下自己代码编写的习惯。不是所有人都有耐心看完你这样的代码的...
2. 学习一下架构的知识(诸如三层架构等)。
3. 好的软件是能反复使用(或者说重用的)。

#9


引用 8 楼  的回复:
另外给LZ一些额外的建议

1. 好好的提升一下自己代码编写的习惯。不是所有人都有耐心看完你这样的代码的...
2. 学习一下架构的知识(诸如三层架构等)。
3. 好的软件是能反复使用(或者说重用的)。


谢谢您耐心的帮助!您指出的的"select * from LifeInsuranceCompany"的确是根源所在。

您说的“好好的提升一下自己代码编写的习惯”是指我目前的代码缺乏精简吗?