La forma más sencilla que puede considerar podría ser TRUNCAR la tabla de destino, luego simplemente guardar la importación XML en ella (con AI desactivada para que use la ID importada si es necesario). El único problema puede ser con los derechos para hacer eso. De lo contrario...
Lo que está tratando de hacer puede casi ser manejado usando el Merge
método. Sin embargo, no puede/no sabrá acerca de filas eliminadas. Dado que el método actúa sobre DataTables
, si se eliminó una fila en la base de datos maestra, simplemente no existirá en el extracto XML (frente a un RowState
de Deleted
). Estos se pueden eliminar con un bucle.
Del mismo modo, cualquier fila nueva puede obtener un PK diferente para un AI int. Para evitar eso, solo use un PK simple que no sea AI en la base de datos de destino para que pueda aceptar cualquier número.
La carga XML:
private DataTable LoadXMLToDT(string filename)
{
DataTable dt = new DataTable();
dt.ReadXml(filename);
return dt;
}
El código de fusión:
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);
}
Por alguna razón, rowsChanged
siempre informa tantos cambios como filas totales. Pero los cambios de la tabla de datos maestra/XML fluyen a través de la otra tabla/destino.
El código de eliminación obtiene una lista de ID existentes, luego determina qué filas deben eliminarse de la tabla de datos de destino según si la nueva tabla XML tiene una fila con esa ID o no. Se eliminan todas las filas que faltan y luego se fusionan las tablas.
La clave es dtSample.Merge(dtMaster,false, MissingSchemaAction.Add);
que fusiona los datos de dtMaster
con dtSample
. El false
param es lo que permite que los cambios XML entrantes sobrescriban los valores en la otra tabla (y eventualmente se guarden en la base de datos).
No tengo idea de si algunos de los problemas, como los PK de IA que no coinciden, son un gran problema o no, pero esto parece manejar todo lo que pude encontrar. En realidad, lo que intenta hacer es Database Synchronization . Aunque con una tabla y solo unas pocas filas, lo anterior debería funcionar.