且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

更新MySQL会返回受影响的行,但实际上不会更新数据库

更新时间:2023-02-07 18:40:02

您可能想要查看的最简单的方法可能是TRUNCATE目标表, XML导入到它(使用AI关闭,因此它使用导入的ID,如果必要)。唯一的问题可能是有权这样做。否则...

The simplest way which you may want to look into might be to TRUNCATE the destination table, then simply save the XML import to it (with AI off so it uses the imported ID if necessary). The only problem may be with the rights to do that. Otherwise...

您尝试执行的操作几乎 可使用 Merge 方法。 由于该方法在 DataTables 上执行,因此如果某行已在master数据库,它将根本不存在于XML提取中(与 已删除 RowState 不同)。

What you are trying to do can almost be handled using the Merge method. However, it can't/won't know about deleted rows. Since the method is acting on DataTables, if a row was deleted in the master database, it will simply not exist in the XML extract (versus a RowState of Deleted). These can be weeded out with a loop.

同样,任何新行对于AI int都可能获得不同的PK。为了防止这种情况,只需在目标数据库中使用一个简单的非AI PK,以便它可以接受任何数字。

Likewise, any new rows may get a different PK for an AI int. To prevent that, just use a simple non-AI PK in the destination db so it can accept any number.

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的更改会流向其他/目标表。

For whatever reason, rowsChanged always reports as many changes as there are total rows. But changes from the Master/XML DataTable do flow thru to the other/destination table.

删除代码获取现有ID列表,然后确定需要哪些行通过新XML表是否具有带有该ID的行从目标DataTable中删除。所有缺少的行都被删除,然后表合并。

The delete code gets a list of existing IDs, then determines which rows needs to be deleted from the destination DataTable by whether the new XML table has a row with that ID or not. All the missing rows are deleted, then the tables are merged.

关键是 dtSample.Merge(dtMaster,false,MissingSchemaAction.Add); $ c>其中合并来自 dtMaster dtSample 的数据。 false param允许传入的XML更改覆盖另一个表中的值(并最终保存到db)。

The key is dtSample.Merge(dtMaster,false, MissingSchemaAction.Add); which merges the data from dtMaster with dtSample. The false param is what allows the incoming XML changes to overwrite values in the other table (and eventually be saved to the db).

我不知道一些问题,如不匹配的AI PK是一个大问题,但是这似乎处理所有我可以找到。实际上,您要做的是数据库同步。虽然有一个表,只有几行,以上应该工作。

I have no idea whether some of the issues like non matching AI PKs is a big deal or not, but this seems to handle all that I could find. In reality, what you are trying to do is Database Synchronization. Although with one table, and just a few rows, the above should work.