C# 将数据从excel导入多个表

C# 将数据从excel导入多个表,c#,sql,excel,import,C#,Sql,Excel,Import,我正在构建一个离线C#应用程序,它将从电子表格中导入数据,并将它们存储在我创建的SQL数据库中(在项目内部)。通过一些研究,我已经能够使用一些代码将静态表导入到与工作表中的列布局完全相同的数据库中 我想做的是让特定的列根据名称转到正确的表中。这样我就可以正确设计数据库,而不仅仅是一个巨大的表来存储所有内容 下面是我用来将几个静态字段导入一个表的代码,我希望能够将导入的数据拆分为多个 最好的方法是什么 public partial class Form1 : Form {

我正在构建一个离线C#应用程序,它将从电子表格中导入数据,并将它们存储在我创建的SQL数据库中(在项目内部)。通过一些研究,我已经能够使用一些代码将静态表导入到与工作表中的列布局完全相同的数据库中

我想做的是让特定的列根据名称转到正确的表中。这样我就可以正确设计数据库,而不仅仅是一个巨大的表来存储所有内容

下面是我用来将几个静态字段导入一个表的代码,我希望能够将导入的数据拆分为多个

最好的方法是什么

public partial class Form1 : Form
    {
        string strConnection = ConfigurationManager.ConnectionStrings
        ["Test3.Properties.Settings.Test3ConnectionString"].ConnectionString;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {


            //Create connection string to Excel work book
            string excelConnectionString =
            @"Provider=Microsoft.Jet.OLEDB.4.0;
            Data Source=C:\Test.xls;
            Extended Properties=""Excel 8.0;HDR=YES;""";

            //Create Connection to Excel work book
            OleDbConnection excelConnection = new OleDbConnection(excelConnectionString);

            //Create OleDbCommand to fetch data from Excel
            OleDbCommand cmd = new OleDbCommand
            ("Select [Failure_ID], [Failure_Name], [Failure_Date], [File_Name], [Report_Name], [Report_Description], [Error] from [Failures$]", excelConnection);

            excelConnection.Open();
            OleDbDataReader dReader;
            dReader = cmd.ExecuteReader();

            SqlBulkCopy sqlBulk = new SqlBulkCopy(strConnection);
            sqlBulk.DestinationTableName = "Failures";
            sqlBulk.WriteToServer(dReader);

        }
您可以尝试ETL(提取转换加载)体系结构:

摘录:一个类将打开该文件并以您知道如何使用的块的形式获取所有数据(通常您从该文件中获取一行并将其数据解析为包含相关数据的字段的POCO对象),并将其放入其他工作流程可以使用的队列中。在这种情况下,您可能要做的第一件事是让Excel打开该文件并将其重新保存为CSV,这样您就可以在流程中将其作为基本文本重新打开并高效地拆分。您还可以读取列名并构建“映射词典”"; 此列的名称为that,因此它转到数据对象的此属性。这个过程应该尽可能快地进行,失败的唯一原因是,给定文件的结构,行的格式与您要查找的不匹配

转换:将文件内容提取到基本行的实例中后,执行任何验证、计算或其他必要的业务规则,以将文件中的行转换为符合域模型的一组域对象。这个过程可以像您需要的那样复杂,但同样,它应该像您在遵守需求中给出的所有业务规则时所能做到的那样简单

Load:现在您在自己的域对象中有了一个对象图,您可以使用您调用的相同持久性框架来处理以任何其他方式创建的域对象。这可以是基本的ADO,一种类似NHibernate或MSEF的ORM,或者是一种活动记录模式,其中的对象知道如何保持它们自己。它不是大容量加载,但它使您不必实现完全不同的持久化模型,只需将基于文件的数据输入数据库即可

一个ETL工作流可以帮助你将重复的任务分成简单的工作单元,从那里你可以识别花费大量时间并考虑并行进程的任务。p> 或者,在调用批量插入例程来处理数据之前,可以通过检测要处理的列,并将它们排列成与批量输入规范匹配的格式,来获取文件并调整其格式。此文件处理器例程可以执行任何您希望它执行的操作,包括将数据分离为多个文件。然而,这是一个一次处理整个文件的大过程,优化或并行处理的机会有限。然而,如果您的加载机制很慢,或者您拥有大量易于消化的数据,那么它最终可能会比设计良好的ETL更快


在任何情况下,我都会尽可能快地从Office格式转换为纯文本(或XML)格式,而且我肯定不会在服务器上安装Office。如果有任何方法可以要求文件在加载之前采用一些易于解析的格式,如CSV,那就更好了。一般来说,在服务器上安装Office是一件非常糟糕的事情,而在服务器应用程序中的OLE操作也不是更好。应用程序将非常脆弱,Office想要告诉您的任何内容都将导致应用程序挂起,直到您登录到服务器并清除对话框。

如果您只对文本感兴趣(而不是格式等),或者您可以将excel文件另存为CSV文件,并解析CSV文件,这很简单。

根据程序的生命周期,我推荐两种选择之一

  • 如果该程序使用寿命很短,或者通常是一个“一次性”项目,我建议使用一系列例程,使用标准SQL解析数据并将数据输入到另一组表中,并根据需要进行一些字符串处理

  • 如果该计划将持续更长时间和/或在日常基础上找到更多用途,我建议实施一个类似于@KeithS建议的解决方案。使用一组定义良好的数据处理步骤,可以获得很大的灵活性。更具体地说,.NET实体框架可能非常适合。 作为奖励,如果您在这方面还不太精通,您可能会发现在第一次使用诸如EF之类的ORM时,您在处理边界之间的数据(xls->sql->等)方面学到了很多


  • 如果您正在寻找与代码更相关的答案,则可以使用以下方法修改代码,以处理较难的列名/不同的表:

        private void button1_Click(object sender, EventArgs e)
        {
            //Create connection string to Excel work book
            string excelConnectionString =
            @"Provider=Microsoft.Jet.OLEDB.4.0;
            Data Source=C:\Test.xls;
            Extended Properties=""Excel 8.0;HDR=YES;""";
    
            //Create Connection to Excel work book
            OleDbConnection excelConnection = new OleDbConnection(excelConnectionString);
    
            //Create OleDbCommand to fetch data from Excel
            OleDbCommand cmd = new OleDbCommand
            ("Select [Failure_ID], [Failure_Name], [Failure_Date], [File_Name], [Report_Name], [Report_Description], [Error] from [Failures$]", excelConnection);
    
            excelConnection.Open();
    
            DataTable dataTable = new DataTable();
            dataTable.Columns.Add("Id", typeof(System.Int32));
            dataTable.Columns.Add("Name", typeof(System.String));
            // TODO: Complete other table columns
            using(OleDbDataReader dReader = cmd.ExecuteReader())
            {
                DataRow dataRow = dataTable.NewRow();
                dataRow["Id"] = dReader.GetInt32(0);
                dataRow["Name"] = dReader.GetString(1);
                // TODO: Complete other table columns
                dataTable.Rows.Add(dataRow);
            }
    
            SqlBulkCopy sqlBulk = new SqlBulkCopy(strConnection);
            sqlBulk.DestinationTableName = "Failures";
            sqlBulk.WriteToServer(dataTable);
        }
    

    现在,您可以控制列的名称以及数据导入到哪些表中。SqlBulkCopy适用于插入大量数据。如果只有少量行,最好创建一个标准数据访问层来插入记录。

    @KeithS:我正在考虑将这种方法用于在一张工作表中包含多个表的excel。你有什么建议吗?