合并的数据行不会在数据库中更新,但添加的数据行会。为什么?

Merged DataRows are not Updated in the database but Added DataRows are. Why?

我目前正在尝试读取大量 excel 文件,这些文件存储在名为 total 的数据表中,然后我需要将其保存到访问数据库中,它现在可以正常工作,但我恐怕随着需要读取的 excel 个文件的数量增加,效率会很低。

我找到了这个 article 并将其用作我写作功能的基础。

        private void writeAccdb()
    {
        if (File.Exists(saveFileDialog1.FileName))
            File.Delete(saveFileDialog1.FileName);
        OleDbConnection conn;
        OleDbDataAdapter adapter;

        ADOX.Catalog cat = new ADOX.Catalog();
        try
        {
            cat.Create("Provider=Microsoft.ACE.OLEDB." + verFound + ".0;Data Source=" + saveFileDialog1.FileName);
        }
        catch
        {
            return;
        }
        cat = null;
        try
        {
            conn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB." + verFound + ".0;Data Source=" + saveFileDialog1.FileName);
            conn.Open();
        }
        catch
        {
            return;
        }
        try
        {
            using (OleDbCommand cmd = new OleDbCommand("CREATE TABLE [Table_1] ([accdb_id] COUNTER PRIMARY KEY, [VALUE] DOUBLE, [TEXT] MEMO);", conn))
            {
                cmd.ExecuteNonQuery();
            }
        }
        catch (Exception ex) { if (ex != null) ex = null;
        }

        adapter = new OleDbDataAdapter("SELECT * FROM [Table_1]", conn);
        OleDbCommandBuilder cb = new OleDbCommandBuilder(adapter);
        DataTable dtMain = new DataTable();
        adapter.Fill(dtMain);



        //Slow process
        foreach (DataRow row in total.Rows)
        {
            dtMain.Rows.Add(row.ItemArray);
        }
        //Slow process



        adapter.Update(dtMain);
        conn.Close();
    }

我试过使用 .Merge() 和 importrow 但我总是得到一个 180kb 的文件,只包含列名和它们所持有的类型但是当我检查 dtmain 时它确实保存了我从 total 中得到的变量,但是当我 itemarray 它工作正常。

虽然我已经在问这个问题了,但当一个文件被创建时,它说程序仍在使用它直到我关闭程序,但据我所知,与文件,我尝试对所有变量使用 dispose 但它仍然存在,这里可能是什么问题?

编辑

所以我的主要问题是为什么 dtMain 在与 total 合并时不起作用,但当单独添加每一行时它却起作用?

编辑 2

用户选择了他们要从中导入所有 excel 个文件的目录

total 被设置为一个新的数据表,所有列都被填充。

使用

读取在目录中找到的所有 excel 文件的迭代
        private OleDbConnection getExcelFile(string file)
    {
        OleDbConnection conn;
        if (verFound != "")
            return new OleDbConnection("Provider=Microsoft.ACE.OLEDB." + verFound + ".0;Data Source=" + file + ";Extended Properties='Excel " + verFound + ".0 XML;HDR=YES;';");
        foreach(string v in versions){
            try{
                conn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB." + v + ".0;Data Source=" + file + ";Extended Properties='Excel " + v + ".0 XML;HDR=YES;';");
                conn.Open();
                conn.Close();
                verFound = v;
                return conn;
            } catch {
                log("Version " + v + " är ej korrekt.");
            }
        }
        return null;
    }

然后我尝试将 excel 文件数据与总数合并,但如果结构不正确,它会被忽略。

合并所有文件后,datagridview 将成为数据源。

现在用户可以选择根据特定条件删除行。

最后是保存过程,因此总体而言,它只是一个带有排除行选项的直接导入。

如有任何帮助,我们将不胜感激。

So my main question is why dtMain when merged with total doesn't work, but when each line is individually added it does?

原因是因为

  1. 当现有的 DataRow 被复制或合并到另一个 DataTable 时,DataRow 的 RowState 保持不变,并且
  2. 当我们使用 OleDbDataAdapter 的 .fill 方法填充 DataTable 时,所有行都是使用 "Unchanged"
  3. 的 RowState 创建的

因此,当您从 Excel 填充上游数据表时,行将作为 "Unchanged" 插入,并且当这些行最终合并到 "total" 数据表时,它们仍然是 "Unchanged".

示例代码:

string excelFileSpec = @"C:\Users\Gord\Desktop\Book1.xlsx";
string excelConnStr =
        "Provider=Microsoft.ACE.OLEDB.12.0;" +
        "Data Source=" + excelFileSpec + ";" +
        "Extended Properties=\"Excel 12.0 Xml;HDR=YES\";";
using (var excelCon = new OleDbConnection(excelConnStr))
{
    using (var excelDA = new OleDbDataAdapter("SELECT * FROM [Sheet1$]", excelCon))
    {
        var total = new DataTable();
        excelDA.Fill(total);
        Console.WriteLine("DataAdapter.fill() put {0} row(s) into \"total\":", total.Rows.Count);
        int i = 0;
        foreach (DataRow r in total.Rows)
        {
            Console.WriteLine("    total row[{0}]: RowState is \"{1}\"", i++, r.RowState);
        }
        DataTable dtMain = total.Clone();
        dtMain.Merge(total);
        Console.WriteLine("dtMain.Merge(total); completed. \"dtMain\" contains {0} row(s):", dtMain.Rows.Count);
        i = 0;
        foreach (DataRow r in dtMain.Rows)
        {
            Console.WriteLine("    dtMain row[{0}]: RowState is \"{1}\"", i++, r.RowState);
        }
    }
}

结果:

DataAdapter.fill() put 1 row(s) into "total":
    total row[0]: RowState is "Unchanged"
dtMain.Merge(total); completed. "dtMain" contains 1 row(s):
    dtMain row[0]: RowState is "Unchanged"

因此,当您的其他 DataAdapter 转到 .Update Access 数据库时,它会看到 "dtMain" 中的所有行都是 "Unchanged" 并且给人的印象是什么都没有要做。

另一方面,当您 .Add 到 "dtMain" 的每一行时,它们将作为 "Added" 插入到 DataTable 中,因此当 .Update 发生时,它实际上确实发送了"Added" 行到 Access 数据库。