5

我正在进行的项目即将完成。我正在加载一个 .MDB 文件,在 DataGrid 上显示内容并尝试在 DataGrid 上获取这些更改并将它们保存回 .MDB 文件。我还将创建一个函数,允许我从一个 .MDB 文件中获取表并将其保存到另一个 .MDB 文件中。当然,如果我不知道如何将更改保存回 .MDB 文件,我将无法执行任何操作。

我对谷歌进行了广泛的研究,但我的问题没有答案。我认为自己是这个特定主题的初学者,所以请不要让答案太复杂——我需要最简单的方法来编辑 .MDB 文件!请提供编程示例。

  1. 假设我已经与 DataGrid 建立了连接。如何获取 Datagrid 所做的更改?我敢肯定这个回答很简单。
  2. 然后我需要知道如何获取这个 Datatable,将它插入到它来自的 Dataset 中,然后获取该 Dataset 并重写 .MDB 文件。(如果有办法只插入已更改的表,我会更喜欢。)

提前谢谢您,如果您需要更多信息,请告诉我。这是我可能要问的关于这个话题的最后一件事……谢天谢地。

编辑:

我正在使用的 .mdb 是Microsoft Access 数据库。(我什至不知道有多个 .mdb 文件)

我知道我不能通过流写入器或任何东西直接写入 .MDB 文件,但有没有办法可以生成一个已经包含 DataSet 信息的 .MDB 文件?或者是否有一种方法可以将表添加到已加载到 DataGrid 中的 .MDB 文件中。必须有办法!

同样,我需要一种在 C# 中以编程方式执行此操作的方法。

编辑:

好的,我的项目相当大,但我使用单独的类文件来处理所有数据库连接。我知道我的设计和来源真的很草率,但它完成了工作。我只和我在互联网上找到的例子一样好。

请记住,我只是以另一种形式连接到 DataGrid。让我知道您是否需要 Datagrid 表单中的代码(不过我不知道您为什么需要它)。DatabaseHandling.cs 处理 2 个 .MDB 文件。所以你会在那里看到两个数据集。我最终将使用它从一个数据集中获取表格并将它们放入另一个数据集中。我只需要弄清楚如何将这些值保存到 .MDB 文件中。

有没有办法做到这一点?一定有办法...

编辑:

根据我的研究和阅读......我认为答案就在我的眼皮底下。使用“更新()”命令。现在,虽然这再次确保实际上有一种简单的方法可以做到这一点,但我仍然面临一个问题,即我不知道如何使用这个更新命令。

也许我可以这样设置:

Oledb.OledbConnection cn = new Oledb.OledbConnection(); 
cn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Staff.mdb"; 
Oledb.OledbCommand cmd = new Oledb.OledbCommand(cn); 
cmd.CommandText = "INSERT INTO Customers (FirstName, LastName) VALUES (@FirstName, @LastName)"; 

我认为可能会这样做,但我不想手动插入任何东西。我想同时做这两个:

  • 获取在 Datagrid 上更改的信息并更新我从中获取的 Access 数据库文件 (.mdb)
  • 创建一个函数,允许我从另一个 Access 数据库文件 (.mdb) 中获取表,并将它们替换为辅助 Access 数据库文件 (.mdb)。这两个文件将使用完全相同的结构,但其中包含不同的信息。

我希望有人对此提出答案……我的项目已经完成,等待的只是一个简单的答案。

再次提前感谢您。

编辑:

好吧……好消息。我已经想出了如何查询 .mdb 文件本身(我认为)。这是代码,它不起作用,因为由于我尝试使用的 sql 命令而出现运行时错误。这将把我带到我的下一个问题。

DatabaseHandling.cs 新增功能代码:

static public void performSynchronization(string table, string tableTwoLocation)
{
    OleDbCommand cmdCopyTables = new OleDbCommand("INSERT INTO" + table + "SELECT * FROM [MS Access;" + tableTwoLocation + ";].[" + table + "]"); // This query generates runtime error
    cmdCopyTables.Connection = dataconnectionA;
    dataconnectionA.Open();
    cmdCopyTables.ExecuteNonQuery();
    dataconnectionA.Close();
}

如您所见,我实际上已经设法对连接本身执行查询,我相信它是实际的 Access .MDB 文件。正如我所说,我对文件执行的 SQL 查询不起作用,并且在使用时会产生运行时错误。

我试图执行的命令应该从 .MDB 文件中获取一个表并覆盖不同 .MDB 文件的相同类型的表。我在上面尝试的 SQL 命令试图直接从 .mdb 文件中获取一个表,然后直接将其放入另一个表中——这不是我想要做的。我想从 .MDB 文件中获取所有信息——将表放入数据表中,然后将所有数据表添加到数据集(我已经完成)。我想为两个 .MDB 文件执行此操作。一旦我有两个数据集,我想从每个数据集中取出特定的表并将它们添加到每个文件中,如下所示:

  • DataSetA >>>>----- [添加表(覆盖它们)] ----->>>> DataSetB
  • DataSetB >>>>----- [添加表(覆盖它们)] ----->>>> DataSetA

我想把那些数据集拿走,然后把它们放回它们来自的每个 Access .MDB 文件中。基本上保持两个数据库同步。

所以我的问题,修改后,是:

  1. 如何创建一个 SQL 查询,通过覆盖现有的同名表将表添加到 .MDB 文件。查询应该能够在运行时动态创建,该数组用我要添加的表名替换变量。
  2. 如何获取 Datagrid 对 DataTable 所做的更改并将它们放回 DataTable(或 DataSet),以便我可以将它们发送到 .MDB 文件?

我试图尽可能详细地说明......因为我相信我没有很好地解释我的问题。现在这个问题已经变得太长了。我只是希望我能更好地解释这一点。:[

编辑:

感谢下面的用户,我想我几乎找到了解决方法——关键字about。下面是我更新的 DatabaseHandling.cs 代码。我收到运行时错误“数据类型不匹配”。考虑到我正在尝试将这些表复制到另一个具有完全相同设置的数据库中,我不知道这怎么可能。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.OleDb;
using System.Data;
using System.IO;

    namespace LCR_ShepherdStaffupdater_1._0
    {
        public class DatabaseHandling
        {
            static DataTable datatableB = new DataTable();
            static DataTable datatableA = new DataTable();
            public static DataSet datasetA = new DataSet();
            public static DataSet datasetB = new DataSet();
            static OleDbDataAdapter adapterA = new OleDbDataAdapter();
            static OleDbDataAdapter adapterB = new OleDbDataAdapter();
            static string connectionstringA = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + Settings.getfilelocationA();
            static string connectionstringB = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + Settings.getfilelocationB();
            static OleDbConnection dataconnectionB = new OleDbConnection(connectionstringB);
            static OleDbConnection dataconnectionA = new OleDbConnection(connectionstringA);
            static DataTable tableListA;
            static DataTable tableListB;

            static public void addTableA(string table, bool addtoDataSet)
            {
                dataconnectionA.Open();
                datatableA = new DataTable(table);
                try
                {
                    OleDbCommand commandselectA = new OleDbCommand("SELECT * FROM [" + table + "]", dataconnectionA);
                    adapterA.SelectCommand = commandselectA;
                    adapterA.Fill(datatableA);
                }
                catch
                {
                    Logging.updateLog("Error: Tried to get " + table + " from DataSetA. Table doesn't exist!");
                }

                if (addtoDataSet == true)
                {
                    datasetA.Tables.Add(datatableA);
                    Logging.updateLog("Added DataTableA: " + datatableA.TableName.ToString() + " Successfully!");
                }

                dataconnectionA.Close();
            }

            static public void addTableB(string table, bool addtoDataSet)
            {
                dataconnectionB.Open();
                datatableB = new DataTable(table);

                try
                {
                    OleDbCommand commandselectB = new OleDbCommand("SELECT * FROM [" + table + "]", dataconnectionB);
                    adapterB.SelectCommand = commandselectB;
                    adapterB.Fill(datatableB);
                }
                catch
                {
                    Logging.updateLog("Error: Tried to get " + table + " from DataSetB. Table doesn't exist!");
                }



                if (addtoDataSet == true)
                {
                    datasetB.Tables.Add(datatableB);
                    Logging.updateLog("Added DataTableB: " + datatableB.TableName.ToString() + " Successfully!");
                }

                dataconnectionB.Close();
            }

            static public string[] getTablesA(string connectionString)
            {
                dataconnectionA.Open();
                tableListA = dataconnectionA.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new Object[] { null, null, null, "TABLE" });
                string[] stringTableListA = new string[tableListA.Rows.Count];

                for (int i = 0; i < tableListA.Rows.Count; i++)
                {
                    stringTableListA[i] = tableListA.Rows[i].ItemArray[2].ToString();
                }
                dataconnectionA.Close();
                return stringTableListA;
            }

            static public string[] getTablesB(string connectionString)
            {
                dataconnectionB.Open();
                tableListB = dataconnectionB.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new Object[] { null, null, null, "TABLE" });
                string[] stringTableListB = new string[tableListB.Rows.Count];

                for (int i = 0; i < tableListB.Rows.Count; i++)
                {
                    stringTableListB[i] = tableListB.Rows[i].ItemArray[2].ToString();
                }
                dataconnectionB.Close();
                return stringTableListB;
            }

            static public void createDataSet()
            {

                string[] tempA = getTablesA(connectionstringA);
                string[] tempB = getTablesB(connectionstringB);
                int percentage = 0;
                int maximum = (tempA.Length + tempB.Length);

                Logging.updateNotice("Loading Tables...");
                for (int i = 0; i < tempA.Length ; i++)
                {
                    if (!datasetA.Tables.Contains(tempA[i]))
                    {
                        addTableA(tempA[i], true);
                        percentage++;
                        Logging.loadStatus(percentage, maximum);
                    }
                    else
                    {
                        datasetA.Tables.Remove(tempA[i]);
                        addTableA(tempA[i], true);
                        percentage++;
                        Logging.loadStatus(percentage, maximum);
                    }
                }

                for (int i = 0; i < tempB.Length ; i++)
                {
                    if (!datasetB.Tables.Contains(tempB[i]))
                    {
                        addTableB(tempB[i], true);
                        percentage++;
                        Logging.loadStatus(percentage, maximum);
                    }
                    else
                    {
                        datasetB.Tables.Remove(tempB[i]);
                        addTableB(tempB[i], true);
                        percentage++;
                        Logging.loadStatus(percentage, maximum);
                    }
                }


            }

            static public DataTable getDataTableA()
            {
                datatableA = datasetA.Tables[Settings.textA];

                return datatableA;
            }
            static public DataTable getDataTableB()
            {
                datatableB = datasetB.Tables[Settings.textB];
                return datatableB;
            }

            static public DataSet getDataSetA()
            {
                return datasetA;
            }

            static public DataSet getDataSetB()
            {
                return datasetB;
            }

            static public void InitiateCopyProcessA()
            {
                DataSet tablesA;
                tablesA = DatabaseHandling.getDataSetA();

                foreach (DataTable table in tablesA.Tables)
                {
                    CopyTable(table, connectionstringB);
                }
            }

            public static void CopyTable(DataTable table, string connectionStringB)
            {
                var connectionB = new OleDbConnection(connectionStringB);
                foreach (DataRow row in table.Rows)
                {
                    InsertRow(row, table.Columns, table.TableName, connectionB);
                }
            }

            public static void InsertRow(DataRow row, DataColumnCollection columns, string table, OleDbConnection connection)
            {
                var columnNames = new List<string>();
                var values = new List<string>();

                for (int i = 0; i < columns.Count; i++)
                {
                    columnNames.Add("[" + columns[i].ColumnName + "]");
                    values.Add("'" + row[i].ToString().Replace("'", "''") + "'");
                }

                string sql = string.Format("INSERT INTO {0} ({1}) VALUES ({2})",
                        table,
                        string.Join(", ", columnNames.ToArray()),
                        string.Join(", ", values.ToArray())
                    );

                ExecuteNonQuery(sql, connection);
            }

            public static void ExecuteNonQuery(string sql, OleDbConnection conn)
            {
                if (conn == null)
                    throw new ArgumentNullException("conn");

                ConnectionState prevState = ConnectionState.Closed;
                var command = new OleDbCommand(sql, conn);
                try
                {
                    prevState = conn.State;
                    if (prevState != ConnectionState.Open)
                        conn.Open();

                    command.ExecuteNonQuery(); // !!! Runtime-Error: Data type mismatch in criteria expression. !!!
                }
                finally
                {
                    if (conn.State != ConnectionState.Closed
                        && prevState != ConnectionState.Open)
                        conn.Close();
                }
            }

            }          
        }

为什么我会收到此错误?两张表完全相同。我究竟做错了什么?最坏的情况,在插入具有不同值的完全相同的结构表之前,如何删除其他 Access .MDB 文件中的表?

伙计,我希望我能弄清楚这一点......

编辑:

好吧,我已经走了一段距离。我的问题已经演变成一个新问题,因此值得单独提问。我已经回答了我的问题,因为现在我知道如何直接对我打开的连接执行查询。谢谢你们!

4

4 回答 4

3

我不确定你已经走了多远,但如果你正在寻找快速拖放操作,你可能想看看创建一个连接的强类型数据集,并使用 DataSources Tool Window 的拖放功能在 Visual Studio 中。

那里肯定有样品,但你会想要的。

  1. 创建一个新的数据集
  2. 从服务器资源管理器中的数据连接树中拖放
  3. 创建一个新表格
  4. 从数据源工具中拖动表格
  5. 窗体上的窗口。

更新:

首先,我不是 100% 了解您的问题。如果您可以在最好的访问文件之间创建一些链接表,那么您可以使用 sql 语句在文件之间复制数据,例如“INSERT INTO Customers SELECT FirstName, LastName FROM File2.Customers”。如果不是这样,我认为您将不得不循环 DataTables 并使用类似于您上次编辑的 INSERT 语句手动插入记录。至于数据网格,您可能必须通过监视 RowChanged 事件(不确定这是否是确切事件)来跟踪更改的内容,甚至在行更改时执行插入/更新语句。

更新:

循环数据表你会做这样的事情。未测试。我刚刚再次更新它以包含 MakeValueDbReady 函数。这也没有经过测试,我不确定我是否正确处理了所有案例甚至所有案例。您真的必须调试 sql 语句并确保它生成正确的值。每个数据库句柄是不同的值。至少以这种方式提取值解析。我还意识到,您应该能够从 DataTable 上的属性中获取它,而不是对 TableName 进行硬编码

void CopyTable(DataTable table, string connectionStringB)
{
    var connectionB = new OleDbConnection(connectionStringB);
    foreach(DataRow row in table.Rows)
    {
        InsertRow(row, table.Columns, table.TableName, connectionB);
    }
}

public static void InsertRow(DataRow row, DataColumnCollection columns, string table, OleDbConnection connection)
{
    var columnNames = new List<string>();
    var values = new List<string>();

    // generate the column and value names from the datacolumns    
    for(int i =0;i<columns.Count; i++)
    {
        columnNames.Add("[" + columns[i].ColumnName + "]");
        // datatype mismatch should be fixed by this function
        values.Add(MakeValueDbReady(row[i], columns[i].DataType));
    }

    // create the sql
    string sql = string.Format("INSERT INTO {0} ({1}) VALUES ({2})",
            table,
            string.Join(", ", columnNames.ToArray()),
            string.Join(", ", values.ToArray())
        );

    // debug the accuracy of the sql here and even copy into 
    // a new Query in Access to test
    ExecuteNonQuery(sql, connection);
}

// as the name says we are going to check the datatype and format the value
// in the sql string based on the type that the database is expecting
public string MakeValueDbReady(object value, Type dataType)
{
    if (value == null)
        return null;

    if (dataType == typeof(string))
    {
        return "'" + value.ToString().Replace("'", "''") + "'"
    }
    else if (dataType == typeof(DateTime))
    {
        return "#" + ((DateTime)value).ToString + "#"
    }
    else if (dataType == typeof(bool))
    {
        return ((bool)value) ? "1" : "0";
    }

    return value.ToString();
}

public static void ExecuteNonQuery(string sql, OleDbConnection conn)
{
    if (conn == null)
        throw new ArgumentNullException("conn");

    ConnectionState prevState = ConnectionState.Closed;
    var command = new OleDbCommand(sql, conn);
    try
    {
        // the reason we are checking the prev state is for performance reasons
        // later you might want to open the connection once for the a batch
        // of say 500 rows  or even wrap your connection in a transaction.
        // we don't want to open and close 500 connections
        prevState = conn.State;
        if (prevState != ConnectionState.Open)
            conn.Open();

        command.ExecuteNonQuery();
    }
    finally
    {
        if (conn.State != ConnectionState.Closed
            && prevState != ConnectionState.Open)
            conn.Close();
    }
}
于 2009-02-05T22:45:40.460 回答
1

要使用对 DataSet(不是 DataGrid,因为这只是 DataSet 上的 UI)所做的更改来更新原始 MDB 文件,只需使用DataAdapter.Update命令。

将表从 1 移动到另一个有点棘手。如果目标中不存在该表,则需要使用SQL CREATE 语句创建它。然后,DataAdapter.Fill中填充一个 DataSet 。循环遍历每一行并通过调用 DataRow.SetAdded 将其状态设置为RowAdded然后,将其从目标数据库传回 DataAdapter.Update 。

编辑:代码在下一个问题上......

于 2009-02-06T04:02:40.087 回答
0

实际上,扩展名为 .mdb 的文件格式不止一种。所以,如果我猜错了,这将是错误的答案。但是,这听起来像是 Microsoft Access 问题。

您不直接写入 MDB 文件。它们被加密和压缩。修改 MDB 文件最简单的方法是通过 Access 加载它并通过提供的方法复制表。

于 2009-02-05T22:28:27.343 回答
0

您如何连接到数据库(.mdb 文件)?你能发布一些示例代码吗?如果您正确连接到它,那么您针对它运行的任何 SQL 操作都应该自动保存在数据库中。

因此,在连接到数据库后,您可以执行 SQL 来创建表、插入/更新/检索数据等。尝试手动构建 .mdb 文件是不可取的。

这是一个例子:

http://www.java2s.com/Code/CSharp/Database-ADO.net/Access.htm

于 2009-02-05T23:02:35.340 回答