Documente Academic
Documente Profesional
Documente Cultură
Y como valor aadido, la utilidad de ejemplo tambin tiene cdigo para: Saber las instancias de SQL Server. Saber las bases de datos de una instancia de SQL Server. Saber si una tabla en concreto existe en una base de datos de SQL. Crear una tabla (la usada en esta aplicacin de ejemplo).
Como vemos, este formulario utiliza los campos que tiene la tabla que vamos a usar, por tanto, si vas a usar otra tabla diferente a la usada en el ejemplo, tendrs que crear tu propio diseo del formulario. En el cdigo he intentado separar el cdigo que depende de los campos, de forma que te resulte fcil de modificar. Empezando por arriba, tenemos un ComboBox (cboInstancias) en el que mostraremos las instancias de SQL Server que hay instaladas en el equipo.
A la derecha, tenemos otro ComboBox (cboBases) en el que mostraremos las bases de datos que tiene la instancia de SQL Server que hayamos seleccionado del primer combo. El botn que est en la parte derecha, (btnConectar), (en la misma fila que los dos combos) nos servir para conectarnos a la base de datos y a la instancia seleccionadas usando autenticacin de Windows. En ese botn se crea la conexin a la base de datos y se asigna el DataAdapter que usaremos para conectar directamente con la base de datos. Por tanto ser en el cdigo de ese botn donde tendrs que escribir todo lo necesario para realizar la conexin, cargar los datos en la tabla (DataTable) y empezar a mostrar los datos. Al pulsar en el botn de conectar, el cdigo comprueba si la tabla de pruebas existe, de no ser as, nos preguntar si la queremos crear. En el GroupBox tenemos los controles para mostrar los datos, navegar entre las filas, actualizar, crear y eliminar registros. Los botones de navegacin (o movimiento) nos servirn para ir a los distintos registros: Primero, anterior, siguiente y ltimo. El botn de Actualizar lo usaremos para actualizar los datos del registro actual. El botn Nuevo lo usaremos para aadir un nuevo registro. Cuando pulsamos en ese botn, se usarn los datos que actualmente tengamos en las cajas de textos, salvo el ID, ya que en la tabla de ejemplo es autonumrico, y por tanto se crea solo. El botn de Eliminar lo usaremos para eliminar el registro que est actualmente activo. Cuando se elimina el registro, los datos permanecen en los controles, por si queremos volver a crearlo, (pulsando en el botn Nuevo), aunque el ID usado ser diferente al mostrado, ya que al crear un nuevo registro (o fila) el valor del campo ID se genera automticamente.
En este mismo evento y en el correspondiente al cambio de seleccin del combo de las instancias, tambin usamos una funcin (basesDeDatos), que recibe como parmetro el nombre de la instancia seleccionada, para saber las bases de datos que tiene la instancia de SQL Server que hemos seleccionado, el cdigo de esa funcin lo puedes ver aqu.
Private Function basesDeDatos(ByVal instancia As String) As String() ' Las bases de datos de SQL Server Dim basesSys() As String = {"master", "model", "msdb", "tempdb"} Dim bases() As String Dim dt As New DataTable ' Usamos la seguridad integrada de Windows Dim sCnn As String = "Server=" & instancia & "; " & _ "database=master; integrated security=yes"
' La orden T-SQL para recuperar las bases de master Dim sel As String = "SELECT name FROM sysdatabases" Try Dim da As New SqlDataAdapter(sel, sCnn) da.Fill(dt)
ReDim bases(dt.Rows.Count - 1) Dim k As Integer = -1 For i As Integer = 0 To dt.Rows.Count - 1 Dim s As String = dt.Rows(i).Item("name").ToString() ' Solo asignar las bases que no son del sistema If Array.IndexOf(basesSys, s) = -1 Then k += 1 bases(k) = s End If Next If k = -1 Then Return Nothing ReDim Preserve bases(k) Return bases
Catch ex As Exception MessageBox.Show(ex.Message, _ "Error al recuperar las bases de la instancia indicada", _ MessageBoxButtons.OK, MessageBoxIcon.Error) End Try Return Nothing End Function
Private Sub Form1_Load( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load
Me.Text = "Ejemplo acceso SQL Server VB" ' ' Limpiar los controles del GroupBox y ' deshabilitarlos hasta que se conecte a la base de datos For Each c As Control In Me.GroupBox1.Controls ' Limpiar los textbox If TypeOf c Is TextBox Then c.Text = "" End If ' Deshabilitarlos c.Enabled = False Next Me.GroupBox1.Enabled = False
Me.GroupBox1.Text = "Debes conectar antes de usar los datos" ' ' Las instancias de SQL Server que hay instaladas Dim instancias() As String instancias = instanciasInstaladas() For Each s As String In instancias If s = "MSSQLSERVER" Then cboInstancias.Items.Add("(local)") Else cboInstancias.Items.Add("(local)\" & s) End If Next cboInstancias.Text = "(local)"
' Los nombres de las bases de datos Dim bases() As String = basesDeDatos("(local)") If Not bases Is Nothing Then Me.cboBases.Items.AddRange(bases) End If ' Seleccionamos la primera base If Me.cboBases.Items.Count > 0 Then cboBases.SelectedIndex = 0 End If End Sub
Me.cboBases.Items.Clear() If Not bases Is Nothing Then Me.cboBases.Items.AddRange(bases) ' Seleccionamos la primera base If Me.cboBases.Items.Count > 0 Then cboBases.SelectedIndex = 0 End If End If End Sub
En la tabla de ejemplo, estamos usando un campo que contiene caracteres que pueden ser conflictivos, en este caso es simplemente un guin, pero podra ser una vocal acentuada, una ee o contener espacios, en este caso lo que hacemos es indicar en el objeto del tipo CommandBuilder que utilice prefijo y sufijo para "envolver" automticamente esos campos conflictivos, esa indicacin la hacemos mediante las propiedades QuotePrefix y QuoteSufix.
Por ltimo creamos el nuevo objeto del tipo DataTable, que ser el que usemos con el mtodo Fill del adaptador, al usar ese mtodo, ser cuando se conecte con la base de datos y asigne a la tabla los datos indicados en la cadena de seleccin (SELECT). En este ejemplo, le indico que traiga todos los datos, pero tambin podra haber seleccionado con una clusula WHERE otros diferentes. Otra cosa importante que debemos tener en cuenta con el cdigo de seleccin (SELECT) es que si en lugar de indicar un asterisco para que se utilicen todos los campos ( SELECT * ), indicamos solo los campos que nos interesan, en las actualizaciones y lecturas de datos solo podremos incluir los campos indicados. Por ejemplo, si hacemos: SELECT ID, Nombre FROM Prueba, tan solo tendremos acceso a esos dos campos, y cualquier intento de acceder a otros campos (aunque sean vlidos y existan en la tabla) dar error. Finalmente habilitamos nuevamente los controles que estn en el GroupBox para que podamos navegar, aadir, eliminar, actualizar y escribir en las cajas de texto, y mostraremos el primer registro, para ello llamamos al cdigo del evento del botn para mostrar el primer registro. Si no hay datos, (es decir, si la tabla no contiene alguna fila), deshabilitamos el botn de actualizar y el de eliminar, para permitir solo aadir nuevos datos.
Private Sub btnConectar_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnConectar.Click ' Conectar y mostrar los datos ' ' La cadena de conexin Dim sCnn As String = "Server=" & cboInstancias.Text & "; " & _ "database=" & cboBases.Text & "; integrated security=yes"
Dim cnn As New SqlConnection(sCnn) If existeTabla(cnn, "Prueba") = False Then If MessageBox.Show("NO existe la tabla Prueba, que es la usada para este ejemplo." & vbCrLf & _ "Quieres crearla?", "No existe la tabla", _ MessageBoxButtons.YesNo) = DialogResult.Yes Then If crearTablaPrueba() = False Then Exit Sub End If Else
' La cadena de seleccin Dim sSel As String = "SELECT * FROM Prueba ORDER BY ID" ' ' Comprobar si hay algn error Try ' Crear un nuevo objeto del tipo DataAdapter da = New SqlDataAdapter(sSel, sCnn) ' Crear los comandos de insertar, actualizar y eliminar Dim cb As New SqlCommandBuilder(da) ' Como hay campos con caracteres especiales, ' al usarlos incluirlos entre corchetes. cb.QuotePrefix = "[" cb.QuoteSuffix = "]" ' Asignar los comandos al DataAdapter ' (se supone que lo hace automticamente, pero...) da.UpdateCommand = cb.GetUpdateCommand da.InsertCommand = cb.GetInsertCommand da.DeleteCommand = cb.GetDeleteCommand ' ' Esta base de datos usa el ID con valores automticos da.MissingSchemaAction = MissingSchemaAction.AddWithKey ' dt = New DataTable ' Llenar la tabla con los datos indicados da.Fill(dt) ' Me.GroupBox1.Enabled = True Me.GroupBox1.Text = "Conexin realizada" ' Habilitar los controles For Each c As Control In Me.GroupBox1.Controls c.Enabled = True Next
' Y mostrar el primer registro If dt.Rows.Count > 0 Then btnFirst_Click(Nothing, Nothing) Else fila = -1 btnActualizar.Enabled = False
btnEliminar.Enabled = False End If Catch ex As Exception MessageBox.Show("ERROR al conectar o recuperar los datos:" & vbCrLf & _ ex.Message, "Conectar con la base", _ MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End Sub
Catch ex As Exception MessageBox.Show("ERROR: " & ex.Message, "Comprobar tabla") Return False End Try
End Function
cmd.ExecuteNonQuery() creada = True Catch ex As Exception MessageBox.Show("Error al crear la tabla:" & vbCrLf & ex.Message) Finally If Not cnn Is Nothing Then If cnn.State = ConnectionState.Open Then cnn.Close() End If End If End Try
Es importante que sepamos que cuando llamamos al mtodo Update del adaptador, se realizan todas las actualizaciones, es decir, no solo aadir nuevos datos, como "se supone" que es lo que hace este mtodo, sino que si hubisemos eliminado filas, o modificado algunas, esas modificaciones tambin se reflejaran en la base de datos.
Debido a cmo funcionan los campos autincrementales, para asegurarnos de que en realidad el valor de ese ID se actualiza correctamente, si es el primer registro que aadimos (o vale cero, como es la comprobacin que hacemos aqu), deberamos volver a leer los datos reales de la base de datos (que ser despus de haber aadido el primer registro) con idea de que ese ID tenga el valor correcto.
Esto no es necesario en los siguientes datos que vayamos aadiendo, ya que en otros casos el valor del ID se asignar correctamente. Como ves, tambin controlamos los errores que se puedan producir... nunca est de ms!
Private Sub btnNuevo_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnNuevo.Click ' Crear un nuevo registro Dim dr As DataRow = dt.NewRow() ' Asignar los datos de los textbox a la fila asignarDatos(dr)
' Aadir la nueva fila a la tabla dt.Rows.Add(dr) ' Guardar fsicamente los datos en la base Try da.Update(dt) dt.AcceptChanges() ' Si es el primer registro de la base, ' volver a leer los datos para actualizar los IDs If CInt("0" & dr("ID").ToString) = 0 Then dt = New DataTable da.Fill(dt) End If ' Posicionarlo en la ltima fila btnLast_Click(Nothing, Nothing) Catch ex As DBConcurrencyException MessageBox.Show("Error de concurrencia:" & vbCrLf & ex.Message) Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub
Si la caja de textos para la fecha no tiene nada, usamos un valor "nulo" para asignar a ese campo. De todas formas, deberamos usar un Try/Catch para comprobar que la fecha asignada es vlida.
Private Sub asignarDatos(ByVal dr As DataRow) ' Usar los datos que hay en los textbox dr("Nombre") = txtNombre.Text
dr("e-mail") = txtEmail.Text If txtFechaAlta.Text = "" Then dr("FechaAlta") = DBNull.Value Else dr("FechaAlta") = txtFechaAlta.Text End If dr("Comentario") = txtComentario.Text End Sub
Dim dr As DataRow = dt.Rows(fila) ' Asignar los datos de los textbox a la fila asignarDatos(dr)
Catch ex As DBConcurrencyException MessageBox.Show("Error de concurrencia:" & vbCrLf & ex.Message) Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub
Try ' Eliminar la fila de la tabla dt.Rows(fila).Delete() ' Actualizar fsicamente la base de datos da.Update(dt) ' Aceptar los cambios en la copia local dt.AcceptChanges() Catch ex As DBConcurrencyException MessageBox.Show("Error de concurrencia:" & vbCrLf & ex.Message) Catch ex As Exception MessageBox.Show(ex.Message) End Try
End Sub
Nota: Si lo que realmente te interesa es que los datos NO se eliminen directamente en la base de datos, (ni se actualicen ni creen nuevos), hasta que tu quieras, la llamada al mtodo Update del adaptador y la llamada al mtodo AcceptChanges de la tabla no deberas llamarla en estos tres mtodos que acabamos de ver, sino que puedes hacerlo, por ejemplo, cuando el usuario "realmente" quiera que todos esos cambios se hagan fsicamente en la base de datos. Pero eso es, como siempre, a tu criterio.
Moverse entre registros, con comandos para ir al primero, al ltimo, al anterior y al siguiente
Para movernos entre los registros usaremos cuatro mtodos, uno para ir al principio, otro para ir al final, otro para ir al registro anterior y otro para el siguiente. En estos cuatro mtodos usaremos un mtodo extra que ser el que se encargue de comprobar si todo est correcto (o casi) y de mostrar los datos adecuados en cada caja de texto. Al igual que antes con el mtodo asignarDatos, lo he puesto por separado, entre otras cosas para facilitar la modificacin del cdigo para otras tablas. Tambin para que no haya que estar repitiendo en el resto de los mtodos las comprobaciones de que el valor de fila indicado est dentro del rango vlido. Ese rango debe estar entre cero para el primer registro y uno menos del nmero total de filas para el ltimo, por tanto, si el valor del nmero de la fila indicado no es correcto, no hacemos nada, simplemente salimos del mtodo. En caso de que sigamos, quiere decir que es un valor de fila correcto, por tanto leemos esa fila (asignndola a una variable de tipo DataRow) y asignamos los valores a las cajas de texto, en este caso si que usamos el valor del campo ID con idea de que veamos ese valor. Por ltimo habilitamos el botn de actualizar y eliminar, ya que se supone que hay datos.
Private Sub mostrarDatos(ByVal f As Integer) Dim uf As Integer = dt.Rows.Count - 1 If f < 0 OrElse uf < 0 Then Exit Sub ' Dim dr As DataRow = dt.Rows(f) txtID.Text = dr("ID").ToString txtNombre.Text = dr("Nombre").ToString
txtEmail.Text = dr("e-mail").ToString txtFechaAlta.Text = dr("FechaAlta").ToString txtComentario.Text = dr("Comentario").ToString ' btnActualizar.Enabled = True btnEliminar.Enabled = True End Sub
Los cuatro mtodos para movernos son los siguientes, veamos que es lo que hacemos en cada uno de ellos, aunque creo que viendo el cdigo queda clara la intencin.
Nota: Como veremos en el cdigo, en realidad no hace falta pasarle ningn parmetro al mtodo mostrarDatos, ya que al tener la variable fila disponible en todo el formulario, pues podramos usar esa variable, pero... lo dejo as por si se te ocurre hacer cambios y no usar esa variable, que hay gente que no le gusta usar variables "globales" al formulario o clase...
Para ir al primero, simplemente asignamos cero a la variable de la fila actual y llamamos al mtodo de mostrar los datos.
Private Sub btnFirst_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnFirst.Click ' Posicionarse en la primera fila fila = 0 ' Mostrar los datos de la fila indicada mostrarDatos(fila) End Sub
Para ir al ltimo, averiguamos cual es la ltima fila, que como vemos es el valor devuelto por la propiedad Count de la coleccin de filas (Rows), menos uno, ya que como sabemos todos los arrays y colecciones de .NET siempre empiezan con el ndice cero.
Private Sub btnLast_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _
Handles btnLast.Click ' Posicionarse en la ltima fila fila = dt.Rows.Count - 1 ' Mostrar los datos de la fila indicada mostrarDatos(fila) End Sub
Para ir al anterior simplemente le restamos uno al valor de la fila actual, pero debemos hacer una comprobacin de que no sea menor de cero, ya que es posible que estemos en el primer registro y pulsemos en el botn de ir al anterior. En caso de que estemos en el primero, seguiremos en ese mismo registro.
Private Sub btnPrev_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnPrev.Click ' Posicionarse en la fila anterior fila = fila - 1 If fila < 0 Then fila = 0 ' Mostrar los datos de la fila indicada mostrarDatos(fila) End Sub
Por ltimo, para ir al siguiente, hacemos lo mismo que antes, pero en lugar de restar uno, lo que hacemos es aadir uno al valor de la fila actual, y en el caso de que sea mayor que la ltima fila, pues nos quedamos en esa ltima fila.
Private Sub btnNext_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnNext.Click ' Posicionarse en la fila siguiente Dim uf As Integer = dt.Rows.Count - 1 fila = fila + 1 If fila > uf Then fila = uf ' Mostrar los datos de la fila indicada mostrarDatos(fila) End Sub
http://www.elguille.info/net/cursoVB.NET/Default.aspx