2008-11-03 6 views

Respuesta

10

En .NET 3.0 utilice el db.GetChangeSet().Updates.Clear() para actualizar, db.GetChangeSet().Inserts.Clear() para el nuevo o db.GetChangeSet().Deletes.Clear() para los elementos eliminados.

En .net 3.5 y superior, el resultado de GetChangeSet() ahora es de solo lectura, inserte la colección en for o foreach y actualice cada tabla ChangeSet como también escribió macías en su comentario.

+19

¿Esta fue la respuesta aceptada? Esto no funciona: las colecciones Actualizaciones/Inserciones/Eliminaciones son de solo lectura. Y la documentación de MSDN dice que estas colecciones se "computaron en el momento de la llamada" (de GetChangeSet()). http://msdn.microsoft.com/en-us/library/system.data.linq.datacontext.getchangeset.aspx – shaunmartin

+0

No funciona para mí (VS2008) - Obtengo excepciones "la colección es de solo lectura" . Pero ponerlo en un ciclo foreach y actualizar cada tabla que está en ChangeSet - funciona. – greenoldman

+0

Sí, esto solo es de solo lectura, esto no funcionará ya que viene de un GetChangeSet() get = readonly –

30

¿Por qué no descartar el contexto de datos y simplemente reemplazarlo con una nueva instancia?

+11

Porque podría haber objetos captados a través del contexto, que podría querer cambiar/usar más adelante. Si descarto el contexto de datos, tengo que buscar esos objetos nuevamente. Este es un servicio de Windows, donde el contexto de datos se mantiene durante mucho tiempo. –

+0

Además, ¿qué sucede si su sitio web es de solo lectura? (Sí, existen) –

+8

DataContext está destinado a ser utilizado en un enfoque _unit of work_ y, por lo tanto, no está destinado a vivir durante mucho tiempo. ver: [Curso de vida de un LINQ to SQL DataContext] (http://blogs.msdn.com/b/dinesh.kulkarni/archive/2008/04/27/lifetime-of-a-linq-to-sql-datacontext). aspx) – mbx

4

El refresco funcionará; sin embargo, debe proporcionar las entidades que desea restablecer.

Por ejemplo

dataContext.Refresh(RefreshMode.OverwriteCurrentValues, someObject); 
+1

Sin embargo, esto afectará a la base de datos para obtener los valores más recientes, no solo revierte a los viejos valores en caché. – Lucas

9

Como dijo Haacked, tan sólo reduce el contexto de datos.

Probablemente no deba mantener el contexto de datos activo durante mucho tiempo. Están diseñados para ser utilizados de forma transaccional (es decir, un contexto de datos por unidad de trabajo atómica). Si mantiene un contexto de datos activo durante mucho tiempo, corre un mayor riesgo de generar una excepción de concurrencia al actualizar una entidad obsoleta.

3

Puede usar GetOriginalEntityState (..) para obtener los valores originales de los objetos, p. Clientes que usan los viejos valores almacenados en caché.

También puede repetir los cambios, p. actualiza y actualiza solo los objetos específicos y no las tablas completas porque la penalización de rendimiento será alta.

foreach (Customer c in MyDBContext.GetChangeSet().Updates) 
     { 
      MyDBContext.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, c); 
     } 

esto revertirá los cambios utilizando datos persistentes en la base de datos.

Otra solución es volcar el contexto de datos que utiliza, utilizando Dispose().

En cualquier caso, es una buena práctica anular los métodos Insertar y Eliminar en la colección de p. Ej. Clientes que usa y agrega, p. una llamada InsertOnSubmit(). Esto resolverá su problema con inserciones y eliminaciones pendientes.

9

Llamar a Clear() en la colección Actualizaciones, Eliminaciones e Inserciones no funciona.

GetOriginalEntityState() puede ser útil, pero solo proporciona los ID para las relaciones de claves foráneas, no las entidades reales, por lo que le quedará un objeto separado.

He aquí un artículo que explica cómo descartar los cambios desde el contexto de datos: http://graemehill.ca/discard-changes-in-linq-to-sql-datacontext

EDIT: Llamar a Refresh) deshará actualizaciones (pero no eliminaciones y las inserciones.

1

Excelente redacción en here, pero aquí hay una copia y pegar del código utilizado.

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 
+0

Gracias por eso; parece que el sitio ya no existe –

+0

Si alguien todavía usa LINQ to SQL, entonces FYI arreglé el enlace :) –

+0

Lamentablemente, este enfoque es terriblemente lento en relación con una gran cantidad de entidades. Pero, sin embargo, un enfoque inteligente. – ViRuSTriNiTy

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

Consulte Linq to SQL - Discard Pending Changes

+0

Wow, me encanta esto, esto funciona muy bien en mi código C# DotNet 4.0. ¡Teddy tú mandas! No entiendo por qué Microsoft no tiene esto integrado en el contexto de datos en primer lugar. Hice un db.SubmitChanges() justo después del DiscardPendingChanges() para verificar si no ocurrieron cambios. Simplemente hermoso. – Omzig

+1

@Omzig Esto puede ser útil en un contexto de larga duración. Cuando en un contexto de vida corta, otra aproximación es simplemente reiniciar el contexto de datos. Así que creo que esa es la razón por la cual Microsoft no incluye este método en el marco de la entidad; suponen que en la mayoría de los casos se trata de un contexto de duración corta. – Teddy

1

Mi solicitud es el estilo de Outlook con un icono para seleccionar una forma activa (ListBox). Antes de permitir que el usuario cambie su contexto, debe aceptar cambios o descartarlos.

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 
    } 
} 
0

Así es como lo hice. Acabo de seguir el ejemplo de Teddy anterior y lo simplifiqué. Tengo una pregunta, ¿por qué molestarse con la actualización de los 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; 
    } 
Cuestiones relacionadas