DataSet Update

31/05/2005 - 05:31 por aventurero | Informe spam
Realmente este consulta ya la he realizado en otro foro, pero lo hago aquí
porque no he encontrado la solución.
He venido trabajando sobre actualización de varios registros y no he
resuelto el problema.
Creo que cada vez me acerco más
Les pido el favor de ayudarme en lo que puedan.
Página ASP.NET VB.NET, SQL Server 2000
EL CODIGO
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim cadsql As String = "SELECT * FROM TablaCliente"
Dim cadenaConexion As String System.Configuration.ConfigurationSettings.AppSettings("ConString")
Dim con As New SqlConnection(cadenaConexion)
Dim cmd As New SqlCommand(cadsql, con)
Dim Asoat As New SqlDataAdapter(cmd)
Dim Ssoat As New DataSet
Dim cantidad As Int32 = 0
Dim row As DataRow
Try
con.Open()
Asoat.Fill(Ssoat, "TablaCliente")
cmd.CommandText = "SELECT * FROM TablaVehiculo"
Asoat.Fill(Ssoat, "TablaVehiculo ")
cmd.CommandText = "SELECT * FROM TablaSuc where codigo = '1'"
Asoat.Fill(Ssoat, "TablaSuc")
For Each row In Ssoat.Tables("TablaVehiculo").Rows
row("motor") = "NEW NEW"
Next
For Each row In Ssoat.Tables("TablaCliente").Rows
row("telefono") = "TELE TELE"
Next

Dim cb As New SqlCommandBuilder(Asoat)
Asoat = cb.DataAdapter
cantidad = Asoat.Update(Ssoat, "TablaSuc")
cantidad = Asoat.Update(Ssoat, "TablaCliente")
cantidad = Asoat.Update(Ssoat, "TablaVehiculo ")
MsgBox1.ShowMessage("Actualización de datos OK")
Catch ex As Exception
MsgBox1.ShowMessage("Falló Actualización en la base de datos: "
& ex.Message)
Return
Finally
con.Close()
End Try
ERROR GENERADO (ex.Message):
"Falta DataColumn 'codigo' en DataTable 'TablaCliente' para SourceColumn
'codigo'."

Pero..
1. La columna "codigo" corresponde es a la tabla "TablaSuc"
2. No genera ningún error cuando no se hacen modificaciones a ninguna tabla
3. El error sale siempre con respecto a la tabla que se ha modificado (en
una de ellas), siempre con una columna de otra

Preguntas similare

Leer las respuestas

#1 Carlos Durán Urenda
31/05/2005 - 17:29 | Informe spam
Hola Aventurero

Primero que nada, te recomendaría que utilizaras un Adaptador de datos para
cada tabla y no estar cambiando el SelectCommand Cada que llenas una tabla,
esto debido a lo siguiente, considera la talba como un origen de datos, y el
adaptador es precisamente eso, un mecanizmo que adapta los datos del origen
de datos para trabajarlos dentro de net. El adaptador no unicamente se
utiliza para obtener los datos, tambien para modificar, insertar y eliminar
del origen de datos.

lo correcto sería un adaptador para cada tabla, por consiguiente SqlCommand
para cada tabla

El error que te produce es por que cambiaste el SelectCommand del adaptador
y tratas de actualizar una tabla que ya no corresponde a ese comando. he ahi
la importancia de usar un adaptador por tabla.

Segundo. Estas utilizando el commandBuilder, pero no estas obteniendo los
comandos necesarios para la actualizacion, eliminacion e insersion de datos,
en este caso tambien te recomiendo crear un CommandBuilder por cada
Adaptador de Datos, mas o menos de la siguiente manera...

Dim con As New SqlConnection(cadenaConexion)

Dim SQL1 as String ="Insturccion SQL Necesaria"
Dim cmd1 As New SqlCommand(SQL1, con)
Dim AD1 As New SqlDataAdapter(cmd1)

Dim SQL2 as String ="Insturccion SQL Necesaria"
Dim cmd2 As New SqlCommand(SQL2, con)
Dim AD2 As New SqlDataAdapter(cmd2)


Dim SQL3 as String ="Insturccion SQL Necesaria"
Dim cmd3 As New SqlCommand(SQL3, con)
Dim AD3 As New SqlDataAdapter(cmd3)

' hasta este punto el adaptador solo esta configurado para leer datos, ya
que no se han
' especificado los comandos de actualizacion, insersion y eliminacion

' AQUI SE CONFIGURAN LOS COMANDOS PARA HACER EL UPDATE

Dim cb1 As New SqlCommandBuilder(AD1)
With AD1
.InsertCommand = cb1.GetInsertCommand
.DeleteCommand = cb1.DeleteCommand
.UpdateCommand = cb1.UpdateCommand
End With
Dim cb2 As New SqlCommandBuilder(AD2)
With AD2
.InsertCommand = cb2.GetInsertCommand
.DeleteCommand = cb21.DeleteCommand
.UpdateCommand = cb2.UpdateCommand
End With
Dim cb3 As New SqlCommandBuilder(AD3)
With AD3
.InsertCommand = cb3.GetInsertCommand
.DeleteCommand = cb3.DeleteCommand
.UpdateCommand = cb3.UpdateCommand
End With
' en este momento ya estan configurados los adaptadores para hacer el
update, observa
' que no fue necesario abrir la conexion

'ahora si puedes hacer los fills
' modificar los datos
' y ejecutar el update de cada adaptador



Saludos
Carlos Durán



"aventurero" escribió en el mensaje
news:
Realmente este consulta ya la he realizado en otro foro, pero lo hago aquí
porque no he encontrado la solución.
He venido trabajando sobre actualización de varios registros y no he
resuelto el problema.
Creo que cada vez me acerco más
Les pido el favor de ayudarme en lo que puedan.
Página ASP.NET VB.NET, SQL Server 2000
EL CODIGO
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim cadsql As String = "SELECT * FROM TablaCliente"
Dim cadenaConexion As String > System.Configuration.ConfigurationSettings.AppSettings("ConString")
Dim con As New SqlConnection(cadenaConexion)
Dim cmd As New SqlCommand(cadsql, con)
Dim Asoat As New SqlDataAdapter(cmd)
Dim Ssoat As New DataSet
Dim cantidad As Int32 = 0
Dim row As DataRow
Try
con.Open()
Asoat.Fill(Ssoat, "TablaCliente")
cmd.CommandText = "SELECT * FROM TablaVehiculo"
Asoat.Fill(Ssoat, "TablaVehiculo ")
cmd.CommandText = "SELECT * FROM TablaSuc where codigo = '1'"
Asoat.Fill(Ssoat, "TablaSuc")
For Each row In Ssoat.Tables("TablaVehiculo").Rows
row("motor") = "NEW NEW"
Next
For Each row In Ssoat.Tables("TablaCliente").Rows
row("telefono") = "TELE TELE"
Next

Dim cb As New SqlCommandBuilder(Asoat)
Asoat = cb.DataAdapter
cantidad = Asoat.Update(Ssoat, "TablaSuc")
cantidad = Asoat.Update(Ssoat, "TablaCliente")
cantidad = Asoat.Update(Ssoat, "TablaVehiculo ")
MsgBox1.ShowMessage("Actualización de datos OK")
Catch ex As Exception
MsgBox1.ShowMessage("Falló Actualización en la base de datos: "
& ex.Message)
Return
Finally
con.Close()
End Try
ERROR GENERADO (ex.Message):
"Falta DataColumn 'codigo' en DataTable 'TablaCliente' para SourceColumn
'codigo'."

Pero..
1. La columna "codigo" corresponde es a la tabla "TablaSuc"
2. No genera ningún error cuando no se hacen modificaciones a ninguna
tabla
3. El error sale siempre con respecto a la tabla que se ha modificado (en
una de ellas), siempre con una columna de otra



Respuesta Responder a este mensaje
#2 aventurero
01/06/2005 - 04:42 | Informe spam
Carlos:
Muchas gracias por por tu respuesta. Me emociona porque esto si me parece
solución, por lo concreta y específica.
Venía empecinado en utilizar un solo Adapter.
Me quedan algunas dudas que quizá tu experiencia pueda discipar:
1. Qué variantes pueden haber cuando leo los datos, los mantengo en la
sesión (con ASP.NET VB.NET), Modifico datos e inserto registros. Y
posteriormente, cuando es el momento se ordena la actualización.
2. Cómo manejo la transaccionalidad para que la actualización se realice
total para todas las tablas o para ninguna.
3. Cómo hago para Padre-Hijos, cuando creo un Padre con un consecutivo
autonumérico para insertar registros en los HIJOS con el consecutivo
generado. Y de igual forma, no se puede actualizar la BD creando padre sin
crear hijos.

Disculpame abuzar de tu bondad.

Atentamente,


Aventurero
Respuesta Responder a este mensaje
#3 aventurero
01/06/2005 - 16:46 | Informe spam
Gracias Carlos
Me has dado bastante material y voy a trabajar para aplicarlo.
No he podido resolver (o entender) lo del autonumérico, pero en la
transaccionalidad en ASP.NET, porque en SQL Server ya lo he practicado. El
principal inconveniente que he tenido es enviar los datatable completos a
Store Procedure, he intentado con xml sin exito.
De nuevo, gracias. Y en posteriormente le molesto la vida con el resultado
de las actualizaciones que voy a practicar.
Atentamente,


Aventurero
Respuesta Responder a este mensaje
#4 Carlos Durán Urenda
01/06/2005 - 16:59 | Informe spam
Bueno

Primero que nada habria que decir que mucha experiencia no tengo, no he
manejado ASP.Net toda via

pero basicamente seria de la siguiente manera

tendrias que abrir la conexion
leer la informacion
cerrar la conexion, para que el recurso esté disponible en lo que el usuario
edita los datos
en este caso los adaptadores convendrian estar definidos a nivel de modulo
para que no tengas que reconfigurarlos al momento de hacer la actualizacion

para el caso de las transacciones, existe el objeto transaction, pero este
lo tendrias que configurar justamente al momento de hacer la actualizacion,
ya que no puedes inicar una transaccion, cerrar la conexion, volverla a
habrir e intentar continuar con la transaccion

el codigo seria como sigue (yo trabajo generalmente con access por lo que
uso oledb, pero en general el codigo deberia ser muy parecido, solo
cambiando por los objetos nativos de SQL)



' creas una transaccion, que en realidad es un puntero al miembro
transaction de la conexion
' observa que no lleva el New
Dim TR As OleDbTransaction

' acostumbro crear datatables que apunten a las tablas del dataset,
para escribir menos
Dim DTPadre As DataTable = DS.Tables("Padre")
Dim DTHijo As DataTable = DS.Tables("Hijo")

' si utilizas vinculacion de controles seria conveniente hacer un
EndEdit del BindingContext

Try
Con.Open()
' CONFIGURA LA TRANSACCION EN LOS DIFERENTES ADAPTADORES
' esto una vez que se abrio la conexion, la transaccion debe
utilizarse antes de
' que se cierre la conexion
TR = Con.BeginTransaction
With ADPadre
.InsertCommand.Transaction = TR
.UpdateCommand.Transaction = TR
.DeleteCommand.Transaction = TR
End With
With ADHijo
.InsertCommand.Transaction = TR
.UpdateCommand.Transaction = TR
.DeleteCommand.Transaction = TR
End With
Dim i As Integer

En este momento te comento que la secuencia de actualizacion / insersion /
eliminacion, cuando se ejecuta el Update, puede tener problemas ya que
"creo" primero inserta y luego elimina, y si por ejemplo durante el proceso
de edicion de datos eliminaste un registro y luego insertaste otro con la
misma clave, el Update primero trataría de insertar, pero marcaria error por
que aun no se elimina el registro, generando un problema con la clave
principal.

Por lo cual es conveniente modificar el orden en el que se ejecutan los
comandos de actualizacion, insersion y eliminacion, para esto se puede
utilizar el metodo Select del Datatable, para obtener solo los registros
eliminados, insertados o modificados, y de paso procesar solo dichos
registros y no todo el contenido de la tabla, haciendo mas eficiente el
proceso


'ELIMINA, COMENZANDO POR LOS DETALLES
' Obtiene solo los registros eliminados por medio del metodo
Select
ADHijo.Update(DTHijo.Select(Nothing, Nothing,
DataViewRowState.Deleted))
ADPadre.Update(DTPadre.Select(Nothing, Nothing,
DataViewRowState.Deleted))


'MODIFICA COMENZANDO POR EL PADRE - el campo clave no deberia
modificarse
' Obtiene solo los registros modificados por medio del metodo
Select
ADPadre.Update(DTPadre.Select(Nothing, Nothing,
DataViewRowState.ModifiedCurrent))
ADHijo.Update(DTHijo.Select(Nothing, Nothing,
DataViewRowState.ModifiedCurrent))

'INSERTA COMENZANDO POR EL PADRE
' Obtiene solo los registros insertados por medio del metodo
Select
ADPadre.Update(DTPadre.Select(Nothing, Nothing,
DataViewRowState.Added))
ADHijo.Update(DTHijo.Select(Nothing, Nothing,
DataViewRowState.Added))

Finalmente, es cuestion de verificar si ocurrio un error, en cuyo caso
habria que hacer un RollBack o de lo contrario un Commit para que todo se
guarde


Catch ex As OleDb.OleDbException
' CUALQUIER ERROR OCURRIDO HARIA QUE LA TRANZACCION
' SE RECHAZARA (ROLLBACK)
TR.Rollback()
TR = Nothing
Catch ex As DBConcurrencyException
' CUALQUIER ERROR OCURRIDO HARIA QUE LA
' TRANZACCION SE RECHAZARA (ROLLBACK)
TR.Rollback()
TR = Nothing
Finally
If Not (TR Is Nothing) Then
' PROCESA EXITOSAMENTE LA TRANASACCION
TR.Commit()
TR = Nothing
End If
Con.Close()
End Try


De esta forma si hay algun error de concurrencia o algun otro tipo de error
en la base de datos, se descartan todos los cambios. Para el caso de las
concurrencias se podrian hacer varias cosas para tratar de resolver el
problema, pero basicamente se trata de volver a leer los datos y determinar
cual es el que permanece, e implica una buena cantidad de codigo, a mi
manera de ver es mas practico (por lo menos para el programador mas comodo)
rechazar los cambios y pedirle al usuario que vuelva a intentarlo.

Espero esto te pueda servir

Saludos
Carlos Durán


"aventurero" escribió en el mensaje
news:
Carlos:
Muchas gracias por por tu respuesta. Me emociona porque esto si me parece
solución, por lo concreta y específica.
Venía empecinado en utilizar un solo Adapter.
Me quedan algunas dudas que quizá tu experiencia pueda discipar:
1. Qué variantes pueden haber cuando leo los datos, los mantengo en la
sesión (con ASP.NET VB.NET), Modifico datos e inserto registros. Y
posteriormente, cuando es el momento se ordena la actualización.
2. Cómo manejo la transaccionalidad para que la actualización se realice
total para todas las tablas o para ninguna.
3. Cómo hago para Padre-Hijos, cuando creo un Padre con un consecutivo
autonumérico para insertar registros en los HIJOS con el consecutivo
generado. Y de igual forma, no se puede actualizar la BD creando padre sin
crear hijos.

Disculpame abuzar de tu bondad.

Atentamente,


Aventurero


Respuesta Responder a este mensaje
#5 Carlos Durán Urenda
01/06/2005 - 17:17 | Informe spam
Disculpa se me paso lo del autonumerico

yo trato de evitar los autonumericos, especialmente cuando se trata de
foliacion, en su lugar tengo un procedimiento que me genera los
autoincrementales y mantengo los valores en una tabla, de forma que tengo un
mayor control sobre estos valores.

Sin embargo el procedimiento seria a grandes rasgos el siguiente...

el problema se presenta basicamente en los nuevos registros, durante el
proceso de edicion no importa realmente el valor que le asignes a la clave
ya que al guardar, la base de datos asignará el autoincremental, de forma
que podrias utilizar un valor X para la clave del registro padre y de los
hijos (incluso podria ser un negativo - eso creo- de forma que no
interfiera con otro registro que ya tengas previamente cargado) obiamente
ese valor no podrias mostralo al usuario ya que en realidad no es el valor
correcto, si requieres mostrarlo al usuario yo te recomendaria lo que te
comento al principio

Al momento de hacer el update, tendrias que obtener uno por uno los
registros que se insertaron para la tabla padre, realizar el método update e
inmeditamente obtener de la base de datos el valor del @@IDENTITY, que es el
valor del incremental, luego tendrias que copiar este valor a los hijos y
realizar el Update para los hijos, esto en un ciclo para cada uno de los
registros padre insertados

Según se, la forma de obtener el @@IDENTITY varia de Access a SQL, por lo
que mejor te recomiendo busques en este mismo foro las respuestas de:
SqlRanger (Jesús López)

y otras que hablan sobre esta cuestion}


Saludos
Carlos Durán











"aventurero" escribió en el mensaje
news:
Carlos:
Muchas gracias por por tu respuesta. Me emociona porque esto si me parece
solución, por lo concreta y específica.
Venía empecinado en utilizar un solo Adapter.
Me quedan algunas dudas que quizá tu experiencia pueda discipar:
1. Qué variantes pueden haber cuando leo los datos, los mantengo en la
sesión (con ASP.NET VB.NET), Modifico datos e inserto registros. Y
posteriormente, cuando es el momento se ordena la actualización.
2. Cómo manejo la transaccionalidad para que la actualización se realice
total para todas las tablas o para ninguna.
3. Cómo hago para Padre-Hijos, cuando creo un Padre con un consecutivo
autonumérico para insertar registros en los HIJOS con el consecutivo
generado. Y de igual forma, no se puede actualizar la BD creando padre sin
crear hijos.

Disculpame abuzar de tu bondad.

Atentamente,


Aventurero


email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaRespuesta Tengo una respuesta
Search Busqueda sugerida