sql >> Base de Datos >  >> RDS >> Mysql

La actualización de MySQL devuelve las filas afectadas, pero en realidad no actualiza la base de datos

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.