Обновление MySQL возвращает затронутые строки, но фактически не обновляет базу данных.

В настоящее время я использую Mono в Ubuntu с MonoDevelop, работаю с DataTable, соответствующей таблице в базе данных, и должен пытаться ее обновить.

В следующем коде используется набор данных, загруженный из XML-файла, который был создан из набора данных.WriteXML на другом компьютере.

try
{
    if(ds.Tables.Contains(s))
    {                        
        ds.Tables[s].AcceptChanges();
        foreach(DataRow dr in ds.Tables[s].Rows)
            dr.SetModified(); // Setting to modified so that it updates, rather than inserts, into the database
        hc.Data.Database.Update(hc.Data.DataDictionary.GetTableInfo(s), ds.Tables[s]);
    }
            }
            catch (Exception ex)
            {
                Log.WriteError(ex);
            }

Это код для вставки/обновления в базу данных.

public override int SQLUpdate(DataTable dt, string tableName)
    {
        MySqlDataAdapter da = new MySqlDataAdapter();
        try
        {
            int rowsChanged = 0;
            int tStart = Environment.TickCount;

            da.SelectCommand = new MySqlCommand("SELECT * FROM " + tableName);
            da.SelectCommand.Connection = connection;

            MySqlCommandBuilder cb = new MySqlCommandBuilder(da);
            da.UpdateCommand = cb.GetUpdateCommand();
            da.DeleteCommand = cb.GetDeleteCommand();
            da.InsertCommand = cb.GetInsertCommand();
            da.ContinueUpdateOnError = true;
            da.AcceptChangesDuringUpdate = true;

            rowsChanged = da.Update(dt);

            Log.WriteVerbose("Tbl={0},Rows={1},tics={2},", dt.TableName, rowsChanged, Misc.Elapsed(tStart));
            return rowsChanged;
            catch (Exception ex)
            {
                Log.WriteError("{0}", ex.Message);
                return -1
            }

Я пробую приведенный выше код, и rowsChanged становится 4183, количество строк, которые я редактирую. Однако когда я использую HeidiSQL для проверки самой базы данных, это вообще ничего не меняет.

Есть ли шаг, который я пропустил?

Редактировать: в качестве альтернативы также будет работать возможность перезаписать все строки в базе данных. Это настройка для обновления удаленных компьютеров с помощью USB-накопителей, заставляющая их соответствовать таблице исходных данных.

Редактировать 2: добавлен дополнительный пример кода, чтобы показать источник DT. DataTable предварительно заполняется в вызывающей функции, и все строки имеют DataRow.SetModified(); применяемый.

Редактировать 3: Дополнительная информация. Таблица заполняется данными из файла XML. Попытка исправления предложена в комментариях.

Редактировать 4: Добавление кода вызова, на всякий случай.

Спасибо за помощь.


person user3169698    schedule 04.08.2016    source источник
comment
Серверы/соединения MySQL обычно имеют параметр, определяющий, возвращать ли затронутые строки или совпавшие строки; возможно, эффективные настройки для этих двух сред различаются.   -  person Uueerdo    schedule 04.08.2016
comment
что в ДТ? Он заполнен в другом месте? Это просто появляется из ниоткуда в этом коде.   -  person Ňɏssa Pøngjǣrdenlarp    schedule 04.08.2016
comment
Добавлена ​​запрошенная информация.   -  person user3169698    schedule 04.08.2016
comment
Я не могу воспроизвести. Убедитесь, что исходное DT заполнено с помощью da.AcceptChangesDuringFill = false;, чтобы все исходные строки воспринимались как новые. Когда я вставляю обратно в другую БД, он правильно сообщает строки, и они есть. Убедитесь, что вы смотрите на правильную БД.   -  person Ňɏssa Pøngjǣrdenlarp    schedule 04.08.2016
comment
DataTable из набора данных, заполненного из XML-файла. Когда я только вставляю, он работает нормально. Но Update, возвращая сообщение о том, что оно затронуло строки, на самом деле не влияет на базу данных.   -  person user3169698    schedule 04.08.2016
comment
Когда более чем один пользователь комментирует, вам нужно использовать @+имя пользователя (например, @user3169698), чтобы кто-то был пропингован. Я только случайно увидел это последнее обновление.   -  person Ňɏssa Pøngjǣrdenlarp    schedule 05.08.2016


Ответы (1)


Самый простой способ, который вы, возможно, захотите изучить, может состоять в том, чтобы ОБРЕЗАТЬ целевую таблицу, а затем просто сохранить в нее импорт XML (с отключенным AI, чтобы при необходимости он использовал импортированный идентификатор). Единственная проблема может быть с правами на это. В противном случае...

То, что вы пытаетесь сделать, можно почти обработать с помощью метода Merge. Однако он не может/не будет знать об удаленных строках. Поскольку метод действует на DataTables, если строка была удалена в базе данных master, она просто не будет существовать в извлечении XML ( против RowState из Deleted). Их можно отсеять с помощью петли.

Точно так же любые новые строки могут получить другой PK для AI int. Чтобы предотвратить это, просто используйте простой PK без AI в целевой базе данных, чтобы он мог принимать любое число.

Загрузка XML:

private DataTable LoadXMLToDT(string filename)
{
    DataTable dt = new DataTable();
    dt.ReadXml(filename);
    return dt;
}

Код слияния:

DataTable dtMaster = LoadXMLToDT(@"C:\Temp\dtsample.xml");
// just a debug monitor
var changes = dtMaster.GetChanges();

string SQL = "SELECT * FROM Destination";
using (MySqlConnection dbCon = new MySqlConnection(MySQLOtherDB))
{
    dtSample = new DataTable();
    daSample = new MySqlDataAdapter(SQL, dbCon);

    MySqlCommandBuilder cb = new MySqlCommandBuilder(daSample);
    daSample.UpdateCommand = cb.GetUpdateCommand();
    daSample.DeleteCommand = cb.GetDeleteCommand();
    daSample.InsertCommand = cb.GetInsertCommand();
    daSample.FillSchema(dtSample, SchemaType.Source);
    dbCon.Open();

    // the destination table
    daSample.Fill(dtSample);

    // handle deleted rows
    var drExisting = dtMaster.AsEnumerable()
                .Select(x => x.Field<int>("Id"));
    var drMasterDeleted = dtSample.AsEnumerable()
                .Where( q => !drExisting.Contains(q.Field<int>("Id")));

    // delete based on missing ID
    foreach (DataRow dr in drMasterDeleted)
        dr.Delete();

    // merge the XML into the tbl read
    dtSample.Merge(dtMaster,false, MissingSchemaAction.Add);

    int rowsChanged = daSample.Update(dtSample);
}

По какой-то причине rowsChanged всегда сообщает столько изменений, сколько всего строк. Но изменения из Master/XML DataTable действительно передаются в другую/целевую таблицу.

Код удаления получает список существующих идентификаторов, а затем определяет, какие строки необходимо удалить из целевого DataTable, исходя из того, есть ли в новой XML-таблице строка с этим идентификатором или нет. Все недостающие строки удаляются, затем таблицы объединяются.

Ключ dtSample.Merge(dtMaster,false, MissingSchemaAction.Add); объединяет данные из dtMaster с dtSample. Параметр false позволяет входящим изменениям XML перезаписывать значения в другой таблице (и, в конечном итоге, сохраняться в базе данных).


Я понятия не имею, являются ли некоторые проблемы, такие как несоответствие AI PK, большой проблемой или нет, но, похоже, это решает все, что я мог найти. На самом деле вы пытаетесь выполнить синхронизацию базы данных. Хотя с одной таблицей и всего несколькими строками вышеописанное должно работать.

person Ňɏssa Pøngjǣrdenlarp    schedule 04.08.2016
comment
После небольшого редактирования заливка и слияние сделали свое дело! Я также благодарю вас за вещь с удаленными строками, хотя мы делаем это немного по-другому. Мне потребовалось 8 часов, чтобы почесать голову, прежде чем вы пришли! - person user3169698; 05.08.2016