PRB: Los comandos modificados por cambios de CommandBuilder vuelven a su estado original

Este artículo se publicó anteriormente con el número E310366
Este artículo se ha archivado. Se ofrece "tal cual" y no se volverá a actualizar.
Síntomas
El objeto CommandBuilder puede volver a generar un comando que intenta modificar durante la próxima llamada al método DataAdapter.Update; en tal caso, se perderán los cambios realizados al comando. Este problema ocurre en las siguientes circunstancias:
  • Si asocia un objeto CommandBuilder con un objeto DataAdapter.
  • Si utiliza el método GetInsertCommand, GetUpdateCommand o GetDeleteCommand del objeto CommandBuilder para asignar explícitamente comandos al objeto DataAdapter.
  • Si modifica uno de los comandos generados por CommandBuilder.
Cuando intenta llamar al método Update del objeto DataAdapter, puede que aparezca el mensaje de error siguiente:
Excepción no controlada del tipo 'System.Data.SqlClient.SqlException' en system.data.dll
Causa
Este problema ocurre porque CommandBuilder modifica dinámicamente los comandos que genera y vuelve a dejar los comandos originales.
Solución
Utilice uno de los métodos siguientes para resolver este problema:
  • No modifique los comandos generados por CommandBuilder. CommandBuilder no modifica los objetos Command creados por usted.
  • Copie los objetos InsertCommand, DeleteCommand y UpdateCommand a un nuevo objeto DataAdapter (consulte la sección "Más información" para ver un ejemplo). La nueva variable DataAdapter debe tener el mismo ámbito, u otro menor, que la anterior variable DataAdapter.
  • No utilice CommandBuilder. Escriba sus propios objetos Command o utilice Visual Data Tools para escribirlos.
Estado
Este comportamiento es una característica del diseño de la aplicación.
Más información

Pasos para reproducir este comportamiento

  1. Cree un nuevo proyecto de aplicación Windows de Visual Basic. Se agregará Form1 al proyecto de manera predeterminada.
  2. Haga doble clic en el formulario y agregue el código siguiente en la parte superior de la ventana Código:
    Imports System.Data.SqlClient
  3. Agregue un control Button a Form1.
  4. Haga doble clic en el botón y agregue el código siguiente al evento Click:
    Dim cn As New SqlConnection()        Dim custDS As New DataSet()        Dim da1 As New SqlDataAdapter()        Dim da2 As New SqlDataAdapter()        Dim dr As DataRow        Dim cb As SqlCommandBuilder        cn.ConnectionString = "server=servername;database=northwind;uid=sa;pwd=password;"        cn.Open()        da1 = New SqlDataAdapter("select * from Customers", cn)        cb = New SqlCommandBuilder(da1)        da1.Fill(custDS, "Customers")        'Obtener los comandos originales.        da1.InsertCommand = cb.GetInsertCommand        da1.DeleteCommand = cb.GetDeleteCommand        da1.UpdateCommand = cb.GetUpdateCommand        Debug.WriteLine("Longitud del comando original: " & da1.InsertCommand.CommandText.Length)        'Modificar el comando Insert.        da1.InsertCommand.CommandText = "select * from customers where customerid=@@identity"        da1.InsertCommand.UpdatedRowSource = UpdateRowSource.FirstReturnedRecord        da2.InsertCommand = da1.InsertCommand        da2.DeleteCommand = da1.DeleteCommand        da2.UpdateCommand = da1.UpdateCommand        'Agregar un registro a la tabla.        Dim tblCust As DataTable        tblCust = custDS.Tables("Customers")        Dim drCust As DataRow        drCust = tblCust.NewRow()        drCust("CustomerID") = "ZYYYY"        drCust("CompanyName") = "Zora's Yummies"        drCust("ContactName") = "Christophe Namby"        drCust("ContactTitle") = "Assistant Manager"        tblCust.Rows.Add(drCust)        'Actualizar el servidor.        Debug.WriteLine("Longitud da1 antes de la inserción: " & da1.InsertCommand.CommandText.Length)        da1.Update(custDS, "Customers")        Debug.WriteLine("Longitud da1 después de la inserción: " & da1.InsertCommand.CommandText.Length)        Debug.WriteLine("longitud da2 antes de la inserción: " & da2.InsertCommand.CommandText.Length)        da2.Update(custDS, "Customers")        Debug.WriteLine("Longitud da2 después de la inserción: " & da2.InsertCommand.CommandText.Length)
  5. Modifique la cadena de conexión para conectarse a Microsoft SQL Server.
  6. Presione la tecla F5 para ejecutar el código.
  7. Ponga como comentario la línea siguiente para resolver este problema:
            da1.Update(custDS, "Customers")
Esta solución funciona porque CommandBuilder enlaza el evento RowUpdating del DataAdapter ("da1"), por lo que sabe cuándo generar los comandos. Cuando copia los comandos a un DataAdapter diferente ("da2"), CommandBuilder ya no está enlazado a sus eventos y no los modifica.

El ámbito de la variable es importante porque si "da1" y SqlCommandBuilder ("cb") quedan fuera del ámbito, y si se recolectan los elementos no utilizados, CommandBuilder configura sus comandos como Nothing (o null en Visual C#). No puede utilizar estos comandos en "da2". Como la recolección de elementos no utilizados se produce en momentos aleatorios, la llamada al método da2.Update puede provocar errores NullReferenceException intermitentes.
not saved take effect
Propiedades

Id. de artículo: 310366 - Última revisión: 02/24/2014 06:07:39 - Revisión: 1.0

Microsoft ADO .NET (incluido con .NET Framework), Microsoft Visual Basic .NET 2002 Standard Edition, Microsoft Visual C# .NET 2002 Standard Edition

  • kbnosurvey kbarchive kbprb kbadonet KB310366
Comentarios