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

时间:2016-08-04 17:03:35

标签: c# mysql database mono dataadapter

我目前在Ubuntu上使用MonoDevelop上的Mono,使用与数据库中的表匹配的DataTable运行,并且应该尝试更新它。

以下代码使用从XML文件加载的数据集,该文件是从另一台计算机上的Dataset.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:添加调用代码,以防万一。

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

您可能想要查看的最简单方法可能是TRUNCATE目标表,然后只需将XML导入保存到它(关闭AI,以便在必要时使用导入的ID)。唯一的问题可能是有权这样做。否则...

您尝试做的事情可以使用Merge方法处理 几乎 。但是,它不能/不会知道已删除的行。由于该方法正在DataTables上运行,如果在主数据库中删除了一行,它将根本不存在于XML提取(与RowState的{​​{1}}对比)。这些可以通过循环淘汰。

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

XML加载:

Deleted

合并代码:

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); } 始终会报告与总行数一样多的更改。但是,Master / XML DataTable的更改会直接传递到另一个/目标表。

删除代码获取现有ID的列表,然后根据新XML表是否具有该ID的行来确定需要从目标DataTable中删除哪些行。删除所有缺失的行,然后合并表。

密钥为rowsChanged,用于合并dtSample.Merge(dtMaster,false, MissingSchemaAction.Add);dtMaster的数据。 dtSample 参数允许传入的XML更改覆盖另一个表中的值(并最终保存到数据库中)。

我不知道像非匹配的AI PK这样的问题是否是一个大问题,但这似乎可以处理我能找到的所有问题。实际上,你要做的是Database Synchronization。虽然有一个表,只有几行,但上面应该有效。