Проблема с C #:Какой самый простой способ для меня загрузить MDB-файл, внести в него изменения и сохранить изменения обратно в исходный файл?

StackOverflow https://stackoverflow.com/questions/518239

Вопрос

Мой проект, над которым я работаю, почти закончен.Я загружаю MDB-файл, отображаю содержимое в сетке данных и пытаюсь получить эти изменения в сетке данных и сохранить их обратно в .MDB-файл.Я также собираюсь создать функцию, которая позволит мне брать таблицы из одного .MDB-файла и сохранять его в другой MDB-файл.Конечно, я не смогу ничего из этого сделать, если не смогу понять, как сохранить изменения обратно в .MDB-файл.

Я тщательно исследовал Google, и там нет ответов на мой вопрос.Я считаю себя новичком в этой конкретной теме, поэтому, пожалуйста, не усложняйте ответы слишком сильно - мне нужен самый простой способ отредактировать MDB-файл!Пожалуйста, приведите примеры программирования.

  1. Предположим, что я уже установил соединение с DataGrid.Как мне получить изменения, внесенные Datagrid?Я уверен, что на этот вопрос достаточно просто ответить.
  2. Затем мне нужно знать, как взять этот Datatable, вставить его в Dataset, из которого он был получен, затем взять этот Dataset и переписать .MDB-файл.(Если есть способ вставить только те таблицы, которые были изменены, я бы предпочел это.)

Заранее благодарю вас, дайте мне знать, если вам понадобится дополнительная информация.Это последнее, что мне, вероятно, придется спросить по этой теме ... Слава богу.

Редактировать:

Файл .mdb , с которым я работаю , является База данных Microsoft Access. (Я даже не знал, что существует несколько MDB-файлов)

Я знаю, что не могу записывать напрямую в .MDB-файл через streamwriter или что-нибудь еще, но есть ли способ, которым я могу сгенерировать MDB-файл с уже имеющейся в нем информацией о наборе данных?ИЛИ есть просто способ, которым я могу добавлять таблицы в MDB-файл, который я уже загрузил в DataGrid.Должен же быть какой-то способ!

Опять же, мне нужен способ сделать это ПРОГРАММНО в 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).Оба файла будут использовать точно такую же структуру, но будут содержать разную информацию.

Я надеюсь, что кто-нибудь придумает ответ на this...my проект завершен, все, что ждет, - это один простой ответ.

Заранее еще раз благодарю вас.

Редактировать:

Ладно ... хорошие новости.Я выяснил, как запросить сам 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();
}

Как вы можете видеть, мне действительно удалось выполнить запрос к самому соединению, которое, как я полагаю, является фактическим доступом .MDB-файл.Однако, как я уже сказал, SQL-запрос, который я выполнил к файлу, не работает и при использовании выдает ошибку времени выполнения.

Предполагается, что команда, которую я пытаюсь выполнить, берет таблицу из MDB-файла и перезаписывает таблицу того же типа из другого .MDB-файла.Команда SQL, которую я попробовал выше, пыталась напрямую взять таблицу из mdb-файла и напрямую поместить ее в другой - это не то, что я хочу сделать.Я хочу взять всю информацию из .MDB-файла - поместить таблицы в Datatable, а затем добавить все таблицы данных в Dataset (что я и сделал). Я хочу сделать это для двух .MDB-файлов.Как только у меня будет два набора данных, я хочу взять определенные таблицы из каждого набора данных и добавить их в каждый файл следующим образом:

  • Набор данных >>>>----- [ Добавить таблицы (Перезаписать их)] ----->>>> DataSetB
  • DataSetB >>>>----- [ Добавить таблицы (Перезаписать их)] ----->>>> Набор данных

Я хочу взять каждый из этих наборов данных, а затем поместить их ОБРАТНО в каждый Access .MDB-файл, из которого они были получены.По сути, синхронизируя обе базы данных.

Итак, мои пересмотренные вопросы таковы:

  1. Как мне создать SQL-запрос, который добавит таблицу в .MDB-файл, перезаписав существующий с тем же именем.Запрос должен иметь возможность создаваться динамически во время выполнения с помощью массива, который заменяет переменную именем таблицы, которое я хочу добавить.
  2. Как мне получить изменения, внесенные Datagrid в DataTable, и поместить их обратно в DataTable (или DataSet), чтобы я мог отправить их в .MDB-файл?

Я постарался рассказать как можно больше ... потому что я считаю, что не очень хорошо объясняю свою проблему.Теперь этот вопрос стал слишком длинным.Я просто хотел бы объяснить это лучше.:[

Редактировать:

Благодаря пользователю ниже, я думаю, что я почти нашел исправление - ключевое слово почти.Вот мой обновленный код 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-файл перед вставкой точно такой же таблицы структуры с разными значениями в ней?

Чувак, я хотел бы просто разобраться в этом...

Редактировать:

Ладно, я прошел некоторое расстояние.Мой вопрос превратился в новый и, таким образом, заслуживает отдельного вопроса.Я получил ответ на свой вопрос, поскольку теперь я знаю, как выполнять запросы непосредственно к открытому мной соединению.Спасибо вам всем!

Это было полезно?

Решение

Я не уверен, как далеко вы продвинулись, но если вы ищете быструю операцию перетаскивания, возможно, вам захочется рассмотреть создание подключаемого строго типизированного набора данных и использование функций перетаскивания окна инструментов DataSources в Visual Studio.

Там определенно есть образцы, но вы наверняка захотите.

  1. Создайте новый набор данных
  2. Перетаскивание из вашего дерева подключений к данным в обозревателе серверов
  3. Создайте новую форму
  4. Перетащите таблицу из инструмента Источники данных
  5. Окно перехода к форме.
  6. вуаля

Обновить:

Во-первых, я не уверен на 100%, что понимаю вашу проблему.Если вы можете создать несколько таблиц ссылок между файлами access, которые были бы лучшими, то вы можете скопировать данные между файлами, используя инструкцию sql типа 'ВСТАВИТЬ В Customers ВЫБЕРИТЕ FirstName, LastName ИЗ File2.Customers'.Если это не вариант and, я думаю, вам придется зацикливать таблицы данных и вставлять записи вручную, используя инструкции INSERT, аналогичные вашему последнему редактированию.Что касается datagrid, вам, вероятно, придется отслеживать, что изменилось, отслеживая событие RowChanged (не уверен, что это точное событие) или даже выполняя инструкции insert / update при изменении строки.

Обновить:

чтобы зациклить datatable, вы бы сделали что-то вроде этого.не проверено.Я только что обновил это снова, чтобы включить функцию MakeValueDbReady .Это также не тестировалось, и я не уверен, что я справился со всеми обращениями или даже со всеми обращениями правильно.Вам действительно нужно будет отладить инструкцию sql и убедиться, что она генерирует правильное значение.Каждая база данных обрабатывает значения is по-разному.По крайней мере, таким образом, анализ значения извлекается.Я также понял, что вместо жесткого кодирования TableName вы должны иметь возможность получить его из свойства DataTable

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();
    }
}

Другие советы

Чтобы обновить исходный MDB-файл с изменениями, внесенными в набор данных (не DataGrid, поскольку это просто пользовательский интерфейс над набором данных) просто используйте Адаптерданных.Обновить команда.

Переместить таблицы из 1 в другую немного сложнее.Если таблица еще не существует в пункте назначения, вам нужно будет создать ее с помощью Инструкция SQL CREATE.Тогда, Адаптерданных.Заполнить набор данных из Источник.Пройдитесь по каждой строке и установите ее состояние на RowAdded, вызвав Поток данных.Добавлен набор.Затем передайте его обратно адаптеру данных.Обновите с помощью пункт назначения База данных.

Редактировать: Код находится в следующем вопросе....

На самом деле существует более одного формата файла с расширением .mdb.Так что, если я угадаю неправильно, это будет неправильный ответ.Но, похоже, это проблема Microsoft Access.

Вы не выполняете запись непосредственно в MDB-файл.Они зашифрованы и сжаты.Самый простой способ изменить MDB-файл - это загрузить его через Access и скопировать таблицы с помощью предоставленных методов.

Как вы подключаетесь к базе данных (файл .mdb)?Не могли бы вы опубликовать какой-нибудь пример кода?Если вы подключаетесь к нему правильно, то любые операции SQL, которые вы выполняете с ним, должны автоматически сохраняться в базе данных.

Таким образом, после подключения к базе данных вы можете выполнить SQL, который будет создавать таблицы, вставлять / обновлять / извлекать данные и т.д.Пытаться создать MDB-файл вручную не рекомендуется.

Вот пример:

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top