Sur Linq to SQL DataContext, je peux appeler SubmitChanges () pour soumettre toutes les modifications.
Ce que je veux, c'est en quelque sorte rejeter toutes les modifications du contexte de données et annuler toutes les modifications (de préférence sans passer par la base de données).
Est-ce possible?
Dans .net 3.0, utilisez db.GetChangeSet().Updates.Clear()
pour les mises à jour, db.GetChangeSet().Inserts.Clear()
pour les nouveaux et db.GetChangeSet().Deletes.Clear()
pour les éléments supprimés.
Dans .net 3.5 et supérieur, le résultat de GetChangeSet () est désormais en lecture seule, bouclez la collection pour ou pour chaque et actualisez chaque table ChangeSet comme le fait aussi macias.
Pourquoi ne pas supprimer le contexte de données et le remplacer simplement par une nouvelle instance?
public static class DataContextExtensions
{
/// <summary>
/// Discard all pending changes of current DataContext.
/// All un-submitted changes, including insert/delete/modify will lost.
/// </summary>
/// <param name="context"></param>
public static void DiscardPendingChanges(this DataContext context)
{
context.RefreshPendingChanges(RefreshMode.OverwriteCurrentValues);
ChangeSet changeSet = context.GetChangeSet();
if (changeSet != null)
{
//Undo inserts
foreach (object objToInsert in changeSet.Inserts)
{
context.GetTable(objToInsert.GetType()).DeleteOnSubmit(objToInsert);
}
//Undo deletes
foreach (object objToDelete in changeSet.Deletes)
{
context.GetTable(objToDelete.GetType()).InsertOnSubmit(objToDelete);
}
}
}
/// <summary>
/// Refreshes all pending Delete/Update entity objects of current DataContext according to the specified mode.
/// Nothing will do on Pending Insert entity objects.
/// </summary>
/// <param name="context"></param>
/// <param name="refreshMode">A value that specifies how optimistic concurrency conflicts are handled.</param>
public static void RefreshPendingChanges(this DataContext context, RefreshMode refreshMode)
{
ChangeSet changeSet = context.GetChangeSet();
if (changeSet != null)
{
context.Refresh(refreshMode, changeSet.Deletes);
context.Refresh(refreshMode, changeSet.Updates);
}
}
}
Reportez-vous à Linq to SQL - Annuler les modifications en attente
Comme Haacked l'a dit, il suffit de supprimer le contexte de données.
Vous ne devriez probablement pas garder le contexte de données en vie pendant longtemps. Ils sont conçus pour être utilisés de manière transactionnelle (c'est-à-dire un contexte de données par unité de travail atomique). Si vous maintenez un contexte de données actif pendant une longue période, vous courez un plus grand risque de générer une exception de simultanéité lorsque vous mettez à jour une entité obsolète.
L'appel de Clear () sur la collection Updates, Deletes and Inserts ne fonctionne pas.
GetOriginalEntityState () peut être utile, mais il ne donne que les ID des relations de clé étrangère, et non les entités réelles, vous laissant ainsi un objet détaché.
Voici un article qui explique comment ignorer les modifications du contexte de données: http://graemehill.ca/discard-changes-in-linq-to-sql-datacontext
EDIT: appeler Refresh () annulera les mises à jour, mais pas les suppressions et les insertions.
L'actualisation fonctionnera, mais vous devrez donner les entités que vous souhaitez réinitialiser.
Par exemple
dataContext.Refresh(RefreshMode.OverwriteCurrentValues, someObject);
Vous pouvez utiliser GetOriginalEntityState (..) pour obtenir les valeurs d'origine des objets, par exemple. Clients utilisant les anciennes valeurs mises en cache.
Vous pouvez également parcourir les modifications, par exemple. met à jour et actualise les objets spécifiques uniquement et non les tables entières, car la pénalité de performance sera élevée.
foreach (Customer c in MyDBContext.GetChangeSet().Updates)
{
MyDBContext.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, c);
}
cela annulera les modifications en utilisant des données persistantes dans la base de données.
Une autre solution consiste à supprimer le contexte de données que vous utilisez à l'aide de Dispose ().
Dans tous les cas, il est recommandé de remplacer les méthodes Insert et Remove dans la collection, par exemple. Les clients que vous utilisez et ajoutez par exemple un appel InsertOnSubmit (). Cela résoudra votre problème avec les insertions et les suppressions en attente.
Mon application est de style Outlook avec une icône pour sélectionner un formulaire actif (ListBox). Avant de permettre à l'utilisateur de changer de contexte, il doit accepter les modifications ou les rejeter.
var changes = db.GetChangeSet();
if ((changes.Updates.Count > 0) || (changes.Inserts.Count > 0) || (changes.Deletes.Count > 0))
{
if (MessageBox.Show("Would you like to save changes?", "Save Changes", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
db.SubmitChanges();
} else
{
//Rollback Changes
foreach (object objToInsert in changes.Inserts)
{
db.GetTable(objToInsert.GetType()).DeleteOnSubmit(objToInsert);
}
foreach (object objToDelete in changes.Deletes)
{
db.GetTable(objToDelete.GetType()).InsertOnSubmit(objToDelete);
}
foreach (object objToUpdate in changes.Updates)
{
db.Refresh(RefreshMode.OverwriteCurrentValues, objToUpdate);
}
CurrentForm.SetObject(null); //Application Code to Clear active form
RefreshList(); //Application Code to Refresh active list
}
}
Excellente rédaction sur ici , mais voici un copier/coller du code utilisé.
Public Sub DiscardInsertsAndDeletes(ByVal data As DataContext)
' Get the changes
Dim changes = data.GetChangeSet()
' Delete the insertions
For Each insertion In changes.Inserts
data.GetTable(insertion.GetType).DeleteOnSubmit(insertion)
Next
' Insert the deletions
For Each deletion In changes.Deletes
data.GetTable(deletion.GetType).InsertOnSubmit(deletion)
Next
End Sub
Public Sub DiscardUpdates(ByVal data As DataContext)
' Get the changes
Dim changes = data.GetChangeSet()
' Refresh the tables with updates
Dim updatedTables As New List(Of ITable)
For Each update In changes.Updates
Dim tbl = data.GetTable(update.GetType)
' Make sure not to refresh the same table twice
If updatedTables.Contains(tbl) Then
Continue For
Else
updatedTables.Add(tbl)
data.Refresh(RefreshMode.OverwriteCurrentValues, tbl)
End If
Next
End Sub
Voici comment je l'ai fait. Je viens de suivre l'exemple de Teddy ci-dessus et de le simplifier. J'ai une question cependant, pourquoi même s'embarrasser du rafraîchissement sur les DELETES?
public static bool UndoPendingChanges(this NtsSuiteDataContext dbContext)
{
if (dbContext.ChangesPending())
{
ChangeSet dbChangeSet = dbContext.GetChangeSet();
dbContext.Refresh(RefreshMode.OverwriteCurrentValues, dbChangeSet.Deletes);
dbContext.Refresh(RefreshMode.OverwriteCurrentValues, dbChangeSet.Updates);
//Undo Inserts
foreach (object objToInsert in dbChangeSet.Inserts)
{
dbContext.GetTable(objToInsert.GetType()).DeleteOnSubmit(objToInsert);
}
//Undo deletes
foreach (object objToDelete in dbChangeSet.Deletes)
{
dbContext.GetTable(objToDelete.GetType()).InsertOnSubmit(objToDelete);
}
}
return true;
}