Borrar registros de dos tablas relacionadas

Tengo (en Visual Basic 2005) un formulario con un DataGridView (DgvAlumnos), un BindingNavigator (BdnAlumnos) y un botón (BtnActualizar) y dos tablas en una base de datos sql-server 2005, la primera se llama Alumno y la otra Matricular. Las dos tablas están relacionadas de 1 a N de forma que yo puedo tener en la tabla matricular varios Dni de alumnos, pero en la tabla Alumno solo puedo tener un Dni porque es la clave principal de la tabla. Cuando cargo el formulario lleno el datagridview (DgvAlumnos) con los datos de la tabla Alumno. Luego utilizo los botones del BindingNavigator para recorrer las filas del datagridview . El problema surge cuando yo selecciono una fila del datagridview y pulso el botón borrar del BindingNavigator para borrar la fila seleccionada. Cuando pulso en el botón BtnActualizar para actualizar la base de datos si el alumno que borro solo aparece en la tabla Alumno, me borra correctamente el registro en la base de datos, pero cuando el alumno esta en la tabla Alumno y también está en la tabla Matricular entonces me da el error siguiente :
Instrucción DELETE en conflicto con la restricción REFERENCE "FK_Matricular_Alumno". El conflicto ha aparecido en la base de datos "C:\USERS\ADMINISTRADOR\DESKTOP\WINDOWSAPPLICATION1\BDESCUELA.MDF", tabla "dbo.Matricular", column 'DniAlumno'. Se terminó la instrucción.
En principio no me debería de dar esa excepción por que yo antes de borrar un alumno de la tabla Alumno borro los registros de ese Alumno de la tabla Matricular (si es que los tiene ). El código es el siguiente:
Public Class Form1
Dim ConAlumnos As SqlConnection
Dim DAAlumnos As SqlDataAdapter
Dim DAMatricular As SqlDataAdapter
Dim BdsAlumnos As New BindingSource
Dim DSAlumnos1 As New DataSet("DSAlumnos")
Dim DSMatricular1 As New DataSet("DSMatricular")
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
ConAlumnos = New SqlConnection
ConAlumnos.ConnectionString = "cadena de conexión"
DAAlumnos = New SqlDataAdapter("select * from Alumno", ConAlumnos)
DAAlumnos.Fill(DSAlumnos1, "Alumno")
BdsAlumnos.DataSource = DSAlumnos1
BdsAlumnos.DataMember = "Alumno"
DgvAlumnos.DataSource = BdsAlumnos
BdnAlumnos.BindingSource = BdsAlumnos
DAMatricular = New SqlDataAdapter("select * from Matricular", ConAlumnos)
DAMatricular.Fill(DSMatricular1, "Matricular")
End Sub
Private Sub BtnActualizar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnActualizar.Click
Dim Parametro1Delete As SqlParameter
DAMatricular.DeleteCommand = New SqlCommand("Delete from Matricular where DniAlumno = @DniAlumno", ConAlumnos)
Parametro1Delete = New SqlParameter("@DniAlumno", SqlDbType.NChar, 9)
Parametro1Delete.SourceColumn = DSMatricular1.Tables("Matricular").Columns("DniAlumno").ToString
Parametro1Delete.SourceVersion = DataRowVersion.Original
DAMatricular.DeleteCommand.Parameters.Add(Parametro1Delete)
Me.BindingContext(DSMatricular1, "Matricular").EndCurrentEdit()
If DSAlumnos1.HasChanges() Then
DAMatricular.Update(DSMatricular1, "Matricular")
DSMatricular1.Tables("Matricular").AcceptChanges()
End If
DAAlumnos.DeleteCommand = New SqlCommand("Delete from Alumno where Dni=@Dni", ConAlumnos)
Parametro1Delete = New SqlParameter("@Dni", SqlDbType.NChar, 9)
Parametro1Delete.SourceColumn = DSAlumnos1.Tables("Alumno").Columns("Dni").ToString
Parametro1Delete.SourceVersion = DataRowVersion.Original
DAAlumnos.DeleteCommand.Parameters.Add(Parametro1Delete)
Me.BindingContext(DSAlumnos1, "Alumno").EndCurrentEdit()
If DSAlumnos1.HasChanges() Then
DAAlumnos.Update(DSAlumnos1, "Alumno")
DSAlumnos1.Tables("Alumno").AcceptChanges()
End If
End Sub
End Class
El caso es que no me funciona lo de borrar primero en la tabla Matricular por eso me salta esa excepción. ¿Sabes dónde está el error?

2 Respuestas

Respuesta
1
El código tal cual lo tienes no tiene problema alguno, ya lo revisé, y lo probé con una base de datos que me creé en access, por que no tengo acceso al sqlserver en este momento, le hice algunas adecuaciones para trabajarlo con oledb, y algunos cambios menores en los nombres de campos que no afectan en nada..
Le puse las relaciones tal cual a la base de datos, y esto funciona de maravilla.
Te recomendaría otras formas de hacerlo, pero por lo que veo esto lo necesitas para practicas escolares.., así que no se me ocurre donde viene el error, tal vez si te lo vuelvo a probar creándolo en sqlserver, pero por el momento ya es tarde y tengo que levantarme temprano a trabajar.
Si no lo has solucionado, trataré de buscartele de nuevo el error mañana, que a simple vista no se lo encontré..
Te dejo el ejemplo de lo que te hice para que veas, que en el código no está el error, toma en cuenta que por ser access tuve que usar oledb en lugar de sql.
Pero vamos que esto aquí funciona al 100%
Imports System. Data. OleDb
Public Class Form1
Dim ConAlumnos As OleDbConnection
Dim DAAlumnos As OleDbDataAdapter
Dim DAMatricular As OleDbDataAdapter
Dim BdsAlumnos As New BindingSource
Dim DSAlumnos1 As New DataSet("DSAlumnos")
Dim DSMatricular1 As New DataSet("DSMatricular")
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ConAlumnos = New OleDbConnection
ConAlumnos.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\AppLearning\Helping\BDEscuela.mdb"
DAAlumnos = New OleDbDataAdapter("select * from Alumnos", ConAlumnos)
DAAlumnos.Fill(DSAlumnos1, "Alumnos")
BdsAlumnos.DataSource = DSAlumnos1
BdsAlumnos.DataMember = "Alumnos"
DGVAlumnos.DataSource = BdsAlumnos
BdnAlumnos.BindingSource = BdsAlumnos
DAMatricular = New OleDbDataAdapter("select * from Matricular", ConAlumnos)
DAMatricular.Fill(DSMatricular1, "Matricular")
End Sub
Private Sub BtnActualizar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnActualizar.Click
Dim Parametro1Delete As OleDbParameter
DAMatricular.DeleteCommand = New OleDbCommand("Delete from Matricular where DniAlumno = @DniAlumno", ConAlumnos)
Parametro1Delete = New OleDbParameter("@DniAlumno", OleDbType.Char, 15)
Parametro1Delete.SourceColumn = DSMatricular1.Tables("Matricular").Columns("DniAlumno").ToString
Parametro1Delete.SourceVersion = DataRowVersion.Original
DAMatricular.DeleteCommand.Parameters.Add(Parametro1Delete)
Me.BindingContext(DSMatricular1, "Matricular").EndCurrentEdit()
If DSAlumnos1.HasChanges() Then
DAMatricular.Update(DSMatricular1, "Matricular")
DSMatricular1.Tables("Matricular").AcceptChanges()
End If
DAAlumnos.DeleteCommand = New OleDbCommand("Delete from Alumnos where DniAlumno=@DniAlumno", ConAlumnos)
Parametro1Delete = New OleDbParameter("@DniAlumno", OleDbType.Char, 15)
Parametro1Delete.SourceColumn = DSAlumnos1.Tables("Alumnos").Columns("DniAlumno").ToString
Parametro1Delete.SourceVersion = DataRowVersion.Original
DAAlumnos.DeleteCommand.Parameters.Add(Parametro1Delete)
Me.BindingContext(DSAlumnos1, "Alumnos").EndCurrentEdit()
If DSAlumnos1.HasChanges() Then
DAAlumnos.Update(DSAlumnos1, "Alumnos")
DSAlumnos1.Tables("Alumnos").AcceptChanges()
End If
End Sub
End Class
No puedo hacerlo en Access, tiene que ser en sql-server 2005, llevo varios días dándole vueltas y nada, no encuentro la solución, si puedes probarlo en el sql-server, te lo agradecería, pruébalo con el código que yo te pasé (exactamente el mismo), si no se te ocurre donde está el fallo pero tienes otra idea .. pues coméntamela si puedes ...
Un Saludo y Gracias !
Conozco otras formas de darle solución a esto, pero respecto al código que me envías no tiene ningún error.
Alguna cosa que puedes hacer por ejemplo
Es eliminar los registros con sqlcommand.
Y después volver a enlazar los objetos, es decir invocar lo mismo que tienes en el form load, para que vuelva a cargar los datos.
Por el momento no puedo seguir probando, por que estoy en el trabajo, pero te dejo esa idea por si te sirve de algo de momento.
En cuanto tenga un rato disponible te sigo ayudando.
No se muy bien a lo que te refieres, he probado a crear otro bindingsource (BdsMatricular) y he hecho los siguiente :
DSMatricular1.Dispose()
DAMatricular.Dispose()
DAMatricular = New SqlDataAdapter("select * from Matricular", ConAlumnos)
DAMatricular.Fill(DSMatricular1, "Matricular")
BdsMatricular.DataSource = DSMatricular1
BdsMatricular.DataMember = "Matricular"
DataGridView1.DataSource = BdsMatricular
BindingNavigator1.BindingSource = BdsMatricular
pero no me funciona. El codigo lo he escrito justo despues de la siguiente comprobación :
If DSAlumnos1.HasChanges() Then
    DAMatricular.Update(DSMatricular1, "Matricular")
    DSMatricular1.Tables("Matricular").AcceptChanges()
End If
Ya encontré la solución . He accedido a las propiedades de la relación en la base de datos y le he especificado que tanto los borrados como las actualizaciones las hiciese en cascada ! Y ya está! Cuando borro un alumno de la tabla alumnos se me borra ese alumno en la tabla matricular automáticamente. Muchas Gracias
Respuesta
1
Puedes utiliar disparadores para que la eliminación sea desde sql o puedes crear una relación para que actualice en cascada por ejemplo si eliminas el nodo principal que te elimine lo demás la columna dNiAlumbo la tienes relacionada con otra tabla por que también puede ser ese el problema
primero checa si tienes otra tabla relacionada con la tabla que quieres eliminar el registro relacionada si es así por eso te manda ese error
para solucionar esto puedes creae un tiger o disparador en sql que te haga la función que tu solo tengas que eliminar el registro de la tabla principal y lo demás lo haga el disparador si no sabes como realizar uno te mando un ejemplo
saludos y espero que te sirva
Muy bien ! He accedido a las propiedades de la relación y le he especificado que tanto los borrados como las actualizaciones las hiciese en cascada ! Y ya está! Cuando borro un alumno de la tabla alumnos se me borra ese alumno en la tabla matricular automáticamente. Muchas Gracias

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas