4

我目前正在将多个 Access 数据库转换为 Xml 文件。我以前做过这个,我仍然有以前项目的代码。但是,这段代码不会让我随心所欲地构建 xml,这是我这次需要做的。我正在使用XDocumentwith for-loops 来实现这一点,但是在 1000 行数据之后它变得非常慢。

阅读 XDocument 的工作原理告诉我XElement.Add实际上复制了整个 xml 代码并在将所有内容粘贴回文件时添加了新元素。如果这是真的,那么这可能就是问题所在。

这是从Access中读写数据到Xml的部分,看看有没有办法保存。转换具有 27 列和 12256 行的数据库需要将近 30 分钟,而只有 500 行的较小数据库大约需要 5 秒。

private void ReadWrite(string file)
{
    using (_Connection = new OleDbConnection(string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Mode=12;Data Source={0}", pathAccess)))
    {
        _Connection.Open();
        //Gives me values from the AccessDB: tableName, columnName, colCount, rowCount and listOfTimeStamps.
        GetValues(pathAccess);

        XDocument doc = new XDocument(new XDeclaration("1.0", "utf-8", "true"), new XElement(tableName));
        for (int rowInt = 0; rowInt < rowCount; rowInt++)
        {
            XElement item = new XElement("Item", new XAttribute("Time", listOfTimestamps[rowInt].ToString().Replace(" ", "_")));
            doc.Root.Add(item);

            //colCount"-1" prevents the timestamp from beeing written again.
            for (int colInt = 0; colInt < colCount - 1; colInt++)
            {
                using (OleDbCommand cmnd = new OleDbCommand(string.Format("SELECT {0} FROM {1} Where TimeStamp = #{2}#", columnName[colInt] , tableName, listOfTimestamps[rowInt]), _Connection))
                {
                    XElement value = new XElement(columnName[colInt], cmnd.ExecuteScalar().ToString());
                    item.Add(value);
                }
            }
            //Updates progressbar
            backgroundWorker1.ReportProgress(rowInt);
        }
        backgroundWorker1.ReportProgress(0);
        doc.Save(file);
    }
}

这是我的旧转换器的代码。这段代码几乎不受数据库大小的影响,12 556 数据库只需要一秒钟的时间来转换。有没有办法合并这两者?

public void ReadWrite2(string file)
{
    DataSet dataSet = new DataSet();
    using (_Connection = new OleDbConnection(string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Mode=12;Data Source={0}", file)))
    {
        _Connection.Open();

        DataTable schemaTable = _Connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });

        foreach (DataRow dataTableRow in schemaTable.Rows)
        {
            string tableName = dataTableRow["Table_Name"].ToString();

            DataTable dataTable = dataSet.Tables.Add(tableName);
            using (OleDbCommand readRows = new OleDbCommand("SELECT * from " + tableName, _Connection))
            {
                OleDbDataAdapter adapter = new OleDbDataAdapter(readRows);
                adapter.Fill(dataTable);
            }
        }
    }
    dataSet.WriteXml(file.Replace(".mdb", ".xml"));
}

编辑:为了澄清,应用程序在执行时会变慢。无论数据库有多大,前 500 次都需要 5 秒。

更新:好的,所以我现在周末回来了,我在代码中做了一个小的调整,通过在一个循环中填充一个锯齿状数组并将它们写入另一个循环中的值来分离读取和写入。这证明了我的理论是错误的,事实上阅读需要花费很多时间。关于如何在不访问循环内的数据库的情况下用值填充数组的任何想法?

UPDATE2:这是切换到DataReader.Read()-loop 并立即收集所有数据后的最终结果。

public void ReadWrite3(string Save, string Load)
    {
        using (_Connection = new OleDbConnection(string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Mode=12;Data Source={0}", Load)))
        {
            _Connection.Open();
            GetValues(_Connection);

            _Command = new OleDbCommand(String.Format("SELECT {0} FROM {1}", strColumns, tables), _Connection);
            XDocument doc = new XDocument(new XDeclaration("1.0", "utf-8", "true"), new XElement("plmslog", new XAttribute("machineid", root)));
            using (_DataReader = _Command.ExecuteReader())
            {
                for (int rowInt = 0; _DataReader.Read(); rowInt++ )
                {
                    for (int logInt = 0; logInt < colCount; logInt++)
                    {

                        XElement log = new XElement("log");
                        doc.Root.Add(log);

                        elementValues = updateElementValues(rowInt, logInt);

                        for (int valInt = 0; valInt < elements.Length; valInt++)
                        {
                            XElement value = new XElement(elements[valInt], elementValues[valInt]);
                            log.Add(value);
                        }
                    }
                }
            }
            doc.Save(Save);
        }
    }
4

3 回答 3

3

原谅我,但我认为你让你的生活变得比它需要的更复杂。如果您使用一个OleDbDataReader对象,您可以打开它并逐行读取 Access 表,而无需将行数据缓存在数组中(因为您已经在 DataReader 中拥有它)。

例如,我有一些示例数据

dbID    dbName  dbCreated
----    ------  ---------
bar     barDB   2013-04-08 14:19:27
foo     fooDB   2013-04-05 11:23:02

以下代码贯穿表格...

static void Main(string[] args)
{
    OleDbConnection conn = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Documents and Settings\Administrator\Desktop\Database1.accdb;");
    conn.Open();

    OleDbCommand cmd = new OleDbCommand("SELECT * FROM myTable", conn);
    OleDbDataReader rdr = cmd.ExecuteReader();

    int rowNumber = 0;
    while (rdr.Read())
    {
        rowNumber++;
        Console.WriteLine("Row " + rowNumber.ToString() + ":");
        for (int colIdx = 0; colIdx < rdr.FieldCount; colIdx++)
        {
            string colName = rdr.GetName(colIdx);
            Console.WriteLine("    rdr[\"" + colName + "\"]: " + rdr[colName].ToString());
        }
    }
    rdr.Close();
    conn.Close();

    Console.WriteLine("Done.");
}

...并产生结果...

Row 1:
    rdr["dbID"]: foo
    rdr["dbName"]: fooDB
    rdr["dbCreated"]: 2013-04-05 11:23:02
Row 2:
    rdr["dbID"]: bar
    rdr["dbName"]: barDB
    rdr["dbCreated"]: 2013-04-08 14:19:27
Done.
于 2013-04-08T18:38:18.410 回答
2

您正在从嵌套循环内部访问数据库(所有行和列)

 using (OleDbCommand cmnd = new OleDbCommand(string.Format("SELECT {0} FROM {1} 

您最好将数据保存在数组或集合中,然后访问数据库。

于 2013-04-05T08:22:35.657 回答
1

简单的数学计算会告诉你原因。(数据量)

27 * 12256 = 330912

27 * 500 = 13500

330912 / 13500 = 24512

所以你的大声明是24512倍!

(浪费时光)

30*60 = 1800

1800 / 5 = 360

所以你的时间是 360 倍大!

您可以看到您的代码似乎没有做坏事。

于 2013-04-05T08:24:51.270 回答