Mysql
 sql >> Base de données >  >> RDS >> Mysql

La mise à jour de MySQL renvoie les lignes affectées, mais ne met pas réellement à jour la base de données

La façon la plus simple que vous voudrez peut-être examiner pourrait être de TRUNCATE la table de destination, puis d'y enregistrer simplement l'importation XML (avec AI désactivé pour qu'elle utilise l'ID importé si nécessaire). Le seul problème peut être avec les droits de le faire. Sinon...

Ce que vous essayez de faire peut presque être manipulé en utilisant le Merge méthode. Cependant, il ne peut pas/ne sera pas au courant des lignes supprimées. Puisque la méthode agit sur DataTables , si une ligne a été supprimée dans la base de données principale, elle n'existera tout simplement pas dans l'extrait XML (par rapport à un RowState de Deleted ). Ceux-ci peuvent être éliminés avec une boucle.

De même, toute nouvelle ligne peut obtenir un PK différent pour un AI int. Pour éviter cela, utilisez simplement un simple PK non-AI dans la base de données de destination afin qu'il puisse accepter n'importe quel nombre.

Le chargement XML :

private DataTable LoadXMLToDT(string filename)
{
    DataTable dt = new DataTable();
    dt.ReadXml(filename);
    return dt;
}

Le code de fusion :

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);
}

Pour une raison quelconque, rowsChanged signale toujours autant de modifications qu'il y a de lignes au total. Mais les modifications de la table de données maître/XML sont transmises à la table autre/destination.

Le code de suppression obtient une liste des ID existants, puis détermine quelles lignes doivent être supprimées du DataTable de destination en fonction du fait que la nouvelle table XML comporte ou non une ligne avec cet ID. Toutes les lignes manquantes sont supprimées, puis les tableaux sont fusionnés.

La clé est dtSample.Merge(dtMaster,false, MissingSchemaAction.Add); qui fusionne les données de dtMaster avec dtSample . Le false param est ce qui permet aux modifications XML entrantes d'écraser les valeurs de l'autre table (et éventuellement d'être enregistrées dans la base de données).

Je ne sais pas si certains des problèmes tels que les PK AI non correspondants sont un gros problème ou non, mais cela semble gérer tout ce que j'ai pu trouver. En réalité, ce que vous essayez de faire est Synchronisation de base de données . Bien qu'avec une table et seulement quelques lignes, ce qui précède devrait fonctionner.