更新 MySQL returns 行受影响,但实际上并没有更新数据库
Updating MySQL returns rows affected, but doesn't actually update the Database
我目前在 Ubuntu 上使用 Mono 和 MonoDevelop,运行 一个数据 Table 匹配数据库中的一个 table,应该尝试更新它.
以下代码使用从 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);
}
这是 inserting/updating 进入数据库的代码。
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 记忆棒更新远程计算机的设置,强制它匹配源数据 table。
编辑 2:添加了更多代码示例以显示 DT 的来源。 DataTable 在调用函数中预填充,所有行都有 DataRow.SetModified();应用。
编辑 3:附加信息。 Table 正在用 XML 文件中的数据填充。尝试在评论中建议修复。
编辑 4:添加调用代码,以防万一。
感谢您的帮助。
您可能想要研究的最简单方法可能是截断目标 table,然后简单地将 XML 导入保存到它(关闭 AI,因此它使用导入的 ID,如果必要的)。唯一的问题可能在于这样做的权利。否则...
您尝试做的事情几乎可以使用Merge
方法来处理。但是,它不能't/won不知道删除的行。因为该方法作用于DataTables
,如果在master数据库中删除了一行,它XML 提取物中根本不存在(相对于 Deleted
的 RowState
)。这些可以用循环清除。
同样,任何新行都可能获得不同的 AI int PK。为防止这种情况,只需在目标数据库中使用一个简单的非 AI PK,以便它可以接受任何数字。
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 的更改确实会流向 other/destination table.
删除代码获取现有 ID 的列表,然后根据新 XML table 是否具有具有该 ID 的行来确定需要从目标 DataTable 中删除哪些行。删除所有缺失的行,然后合并 table。
键是 dtSample.Merge(dtMaster,false, MissingSchemaAction.Add);
,它合并了来自 dtMaster
和 dtSample
的数据。 false
参数允许传入的 XML 更改覆盖另一个 table 中的值(并最终保存到数据库)。
我不知道像不匹配的 AI PK 这样的问题是否是个大问题,但这似乎可以解决我能找到的所有问题。实际上,您要做的是 Database Synchronization。尽管有一个 table,并且只有几行,但上面的方法应该有效。
我目前在 Ubuntu 上使用 Mono 和 MonoDevelop,运行 一个数据 Table 匹配数据库中的一个 table,应该尝试更新它.
以下代码使用从 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);
}
这是 inserting/updating 进入数据库的代码。
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 记忆棒更新远程计算机的设置,强制它匹配源数据 table。
编辑 2:添加了更多代码示例以显示 DT 的来源。 DataTable 在调用函数中预填充,所有行都有 DataRow.SetModified();应用。
编辑 3:附加信息。 Table 正在用 XML 文件中的数据填充。尝试在评论中建议修复。
编辑 4:添加调用代码,以防万一。
感谢您的帮助。
您可能想要研究的最简单方法可能是截断目标 table,然后简单地将 XML 导入保存到它(关闭 AI,因此它使用导入的 ID,如果必要的)。唯一的问题可能在于这样做的权利。否则...
您尝试做的事情几乎可以使用Merge
方法来处理。但是,它不能't/won不知道删除的行。因为该方法作用于DataTables
,如果在master数据库中删除了一行,它XML 提取物中根本不存在(相对于 Deleted
的 RowState
)。这些可以用循环清除。
同样,任何新行都可能获得不同的 AI int PK。为防止这种情况,只需在目标数据库中使用一个简单的非 AI PK,以便它可以接受任何数字。
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 的更改确实会流向 other/destination table.
删除代码获取现有 ID 的列表,然后根据新 XML table 是否具有具有该 ID 的行来确定需要从目标 DataTable 中删除哪些行。删除所有缺失的行,然后合并 table。
键是 dtSample.Merge(dtMaster,false, MissingSchemaAction.Add);
,它合并了来自 dtMaster
和 dtSample
的数据。 false
参数允许传入的 XML 更改覆盖另一个 table 中的值(并最终保存到数据库)。
我不知道像不匹配的 AI PK 这样的问题是否是个大问题,但这似乎可以解决我能找到的所有问题。实际上,您要做的是 Database Synchronization。尽管有一个 table,并且只有几行,但上面的方法应该有效。