realizar altas
TRANSCRIPT
Realizar altas, bajas y modificaciones con Visual Basic .NET y SQL SERVER 2005
Posted by jororague under SQL SERVER 2005 | Etiquetas: SQL SERVER 2005, VISUAL BASIC |
[24] Comments
Atendiendo a todos los usuarios de Visual Basic, vamos a realizar el uso de Procedmientos
Almacenados en SQL Server 2005y Visual Basic. El primer paso , es diseñar nuestro formulario.
Hay que considerar que este ejemplo es similar al que hice con Visual C#. Los elementos a
utilizar son:
SQLConnection
SQL Command
Stored Procedured SQL SERVER 2005
Si ya tenemos el formulario, ahora hay que agregarle el código. Empezaremos por agregarle en
el encabezado antes de Public Class Form1 esto:
Imports System.Data.SqlClient
Este es mi formulario de ejemplo, es una pantalla para dar de alta a los clientes, en ella solo voy
a estar afectando a los campos clave, nombre, direccion y negocio. Hay que agregrar una nueva
conexion a una base de datos declaramos esto agregandole la cadena de conexión.
Dim cnn As SqlConnection
Dim cmd As SqlCommand
Dim dr As DataRow
Dim conexion As String = “Data Source=.;Initial Catalog=dbDemo;Integrated Security=true”
Coloreo la linea de la conexion porque es importante recordar lo siguiente:
Data Source: Se debe indicar el nombre del servidor, si se tiene SQLSERVER Express, sera
necesario darselo, si se cuenta con una versión superior, podemos utilizar unicamente el .
(punto)
Initial Catalog: Debemos colocar el nombre de la base de datos a utilizar.
Botón Altas.
Primero hay que crear el procedimiento almacenado, en la venta de Server Explorer , hay que
escoger la Base de Datos, y de ahi la carpeta de Stored Procedure, damos un clic con el boton
derecho y escogemos Add New Stored Procedure
Aqui vamos a crear los procedimientos almacenados (stored procedure).
Esto hará que muestre una pantalla para editar el respectivo código en SQL, los siguientes
procedimientos están compuestos de dos partes, la primera donde se declaran los parametros a
utilziar, y en la segunda donde se realiza la transacción SQL.
El procedimiento de Insertar un registro queda de esta forma, recuerda que el nombre que le
des al Store Proceudure será como se almacenará y se llamará desde tu programa en VS.
Stored Procedure Altas
ALTER PROCEDURE dbo.spAltaCliente
@prmId int,
@prmNombre nvarchar(50),
@prmDireccion nvarchar(50),
@prmNegocio nvarchar(50)
AS
INSERT INTO CLIENTES (ID,NOMBRE,DIRECCION,NEGOCIO)
VALUES (@prmId,@prmNombre,@prmDireccion,@prmNegocio)
RETURN
Código del Botón Altas
cnn = New SqlConnection(conexion)
cnn.Open();
cmd=New SqlCommand(“spAltaCliente”,cnn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add(“@prmClave”, SqlDbType.Int).Value = Convert.ToInt16(TextBox1.Text)
cmd.Parameters.Add(“@prmNombre”, SqlDbType.NVarChar).Value = TextBox2.Text
cmd.Parameters.Add(“@prmDireccion”, SqlDbType.NVarChar).Value = TextBox3.Text
cmd.Parameters.Add(“@prmNegocio”, SqlDbType.NVarChar).Value = TextBox4.Text
cmd.ExecuteNonQuery()
MessageBox.Show(“Cliente Activado”)
TextBox1.Text = “”
TextBox2.Text = “”
TextBox3.Text = “”
TextBox4.Text = “”
Stored Procedure Eliminar
CREATE PROCEDURE dbo.spEliminaCliente
@prmId int
AS
DELETE FROM CLIENTES WHERE ID=@prmId
RETURN
Código del Butón Eliminar
cnn = New SqlConnection(conexion)
cnn.Open()
cmd = New SqlCommand(“spEliminaCliente”, cnn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add(“@prmClave”, SqlDbType.Int).Value = Convert.ToInt16(TextBox1.Text)
cmd.ExecuteNonQuery()
MessageBox.Show(“Cliente ELIMINADO”)
TextBox1.Text = “”
TextBox2.Text = “”
Stored Procedure Modificar
CREATE PROCEDURE dbo.spModificaCliente
@prmId int,
@prmNombre nvarchar(40)
AS
UPDATE clientes SET nombre=@prmNombre WHERE Id=@prmId
RETURN
Código del Botón Modificar
cnn = New SqlConnection(conexion)
cnn.Open()
cmd = new SqlCommand(“spModificaCliente”, cnn)
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(“@prmId”, SqlDbType.Int).Value = Convert.ToInt16(TextBox1.Text)
cmd.Parameters.Add(“@prmNombre”, SqlDbType.NVarChar).Value = TextBox2.Text
cmd.ExecuteNonQuery()
MessageBox.Show(“Cliente Modificado”)
textBox1.Text = “”
textBox2.Text = “”
Y les anexo el botón de consulta mas tarde.
Saludos!!!
el Guille, la Web del Visual Basic, C#, .NET y más...
Lo+ - WinFX - .NET - ADO.NET - ASP.NET - Cómo... - Colabora - VB6 - API - HTML - Vista - Links - Foros
ADO.NET
Ejemplo de acceso a datos a una base de SQL ServerPublicado: 19/Abr/2003Actualizado: 21/May/2003
En este ejemplo veremos cómo acceder a una base de datos de SQL Server, usando los
objetos del espacio de nombres System.Data.SqlClient.
Los conceptos que se tratarán serán los siguientes:
- Crear una conexión a la base de datos.
- Mostrar las tablas de la base de datos indicada.
- Mostrar las columnas (o campos) de una tabla.
- Crear un DataAdapter para acceder a los datos devueltos por una consulta.
- Crear un DataSet basado en los datos asociados al DataAdapter.
- Crear nuevos registros.
- Modificar registros.
- Eliminar registros.
- Mostrar el contenido de la tabla en un control ListView.
Nota:
También puedes ver estos mismos conceptos, pero con una base de datos de Access.
Si notas parecido entre esta página y la de Access, no te extrañe, ya que son hermanitas,
pero cada una de ellas mostrando los datos de tipos de bases distintas.
Los objetos a usar en el proyecto.
Los objetos que vamos a usar en este ejemplo, en su gran mayoría residen en el espacio de
nombres System.Data.SqlClient, aunque también se usarán objetos genéricos (DataSet,
DataRow, DataColumn) que residen en System.Data.
Para que nos sea más fácil declarar esos objetos, importaremos el espacio de nombres
System.Data.SqlClient y dado que usaremos procedimientos genéricos, estos los
incluiremos en un módulo, al que llamaremos: ADONETUtil, veamos el código con las
declaraciones de los objetos que usaremos en el proyecto:
'------------------------------------------------------------------------------
' Prueba de acceso a base de tipo SQL Server con ADO.NET (25/May/02)
' Módulo con las declaraciones de objetos
'
' ©Guillermo 'guille' Som, 2002-2003
'------------------------------------------------------------------------------
Imports System.Data.SqlClient
Module ADONETUtil
Friend dbConnection As Data.SqlClient.SqlConnection
Friend dbCommand As Data.SqlClient.SqlCommand
Friend dbDataReader As Data.SqlClient.SqlDataReader
'
Friend dbDataTable As Data.DataTable
Friend dbDataSet As Data.DataSet
Friend dbDataAdapter As Data.SqlClient.SqlDataAdapter
'
Friend CadenaConexion As String
Friend CadenaSelect As String
'
'
Friend ArchivoDatos As String
Friend NombreTabla As String = "Tabla1"
'
La variable CadenaConexion será la cadena con la que conectaremos a la base de datos.
La variable CadenaSelect será el código SQL que usaremos para acceder a la tabla de esa
base de datos.
La variable ArchivoDatos será el nombre completo de la base de datos (Path incluido).
La variable NombreTabla será el nombre que usaremos para identificar a los datos que
cargaremos en el objeto DataAdapter, ese nombre no tiene nada que ver con el nombre de
la tabla a la que vamos a acceder, es sólo un nombre que usaremos con los distintos objetos
de ADO.NET.
Conectar a una base de datos de SQL Server
Para conectar a la base de datos y crear los objetos que cargarán la tabla (definida en la
consulta SQL contenida en la variable CadenaSelect), vamos a crear un procedimiento en
el mismo módulo ADONETUtil:
Friend Sub Conectar(Optional ByVal nombreBaseDatos As String = "", _
Optional ByVal commandString As String = "")
If nombreBaseDatos = "" Then
nombreBaseDatos = ArchivoDatos
End If
ArchivoDatos = nombreBaseDatos
If ArchivoDatos = "" Then
Exit Sub
End If
'
If CadenaSelect = "" Then
CadenaSelect = "SELECT * FROM Table1"
End If
If commandString = "" Then
commandString = CadenaSelect
End If
CadenaSelect = commandString
'
If CadenaConexion = "" Then
'
' Nota: Deberías cambiar el nombre del equipo, etc. (16/Abr/03)
'
CadenaConexion = "data source=GUILLEACER\NETSDK;" & _
"initial catalog=" & ArchivoDatos & ";" & _
"integrated security=SSPI;persist security info=True;" & _
"workstation id=GUILLEACER;packet size=4096"
End If
'
Try
dbConnection = New Data.SqlClient.SqlConnection(CadenaConexion)
Catch e As Exception
MessageBox.Show("Error al crear la conexión:" & vbCrLf & e.Message)
Exit Sub
End Try
'
dbConnection.Open()
'
dbDataSet = New Data.DataSet()
'
dbDataAdapter = New Data.SqlClient.SqlDataAdapter(CadenaSelect, dbConnection)
'
Dim commandBuilder As New Data.SqlClient.SqlCommandBuilder(dbDataAdapter)
'
dbDataAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey
Try
dbDataAdapter.Fill(dbDataSet, NombreTabla)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
'
End Sub
A este procedimiento se le pueden indicar dos parámetros:
El primero indicará el nombre de la base de datos de SQL Server, mientras que el segundo
será la instrucción SQL que nos permitirá acceder a la tabla. Cuando veamos el código del
formulario, tendremos ocasión de ver cómo se llama a este procedimiento.
Lo que aquí tenemos que destacar es lo siguiente:
La cadena de conexión deberíamos tenerla asignada antes de llamar a este procedimiento,
de no ser así, se usará la que hemos indicado en el código, aunque deberías cambiarla para
adaptarla a tu configuración.
Creamos un nuevo objeto del tipo DataSet, que será el que nos permita acceder a los datos.
Creamos un objeto del tipo DataAdapter, este será el que realmente nos permita acceder a
los datos físicos de la base de datos, primero para rellenar el DataSet y posteriormente para
actualizar los cambios realizados en la base de datos.
Es importante saber que los datos contenidos en el objeto DataSet están en memoria y se
acceden y manipulan de forma independiente, sin ninguna relación directa con la base de
datos original. Para que los cambios realizados en memoria se puedan reflejar de forma
permanente en la base de datos, tenemos que usar el objeto DataAdapter.
Una vez creado el DataAdapter, al que se le indica la cadena de selección y la cadena de
conexión o el objeto del tipo Connection. En este caso, le he indicado el objeto
Connection, pero si no queremos crear una conexión permanente, también podemos usar la
misma cadena de conexión usada para crear el objeto Connection en lugar de ese objeto.
Para poder realizar cambios en la base de datos, hay que indicarle al DataAdapter los
comandos SQL que habría que usar para añadir, modificar y eliminar, pero esos comandos
se pueden crear de forma automática creando un nuevo objeto del tipo CommandBuilder,
al que se le pasará como parámetro el adaptador que usará dichos comandos, en realidad el
objeto CommandBuilder no se usa nada más que para que de esta forma se asignen dichos
comandos de actualización de datos.
Si la tabla a la que queremos acceder tiene clave principal (cosa que es común o debería
serlo en todas las tablas), le indicamos mediante la asignación a la propiedad
MissingSchemaAction el valor de añadir con clave. Si no hacemos esta asignación y la
tabla tiene un campo que se incrementa automáticamente, no podríamos crear varios
registros (o filas) en memoria y después actualizar esas nuevas filas de forma permanente,
ya que nos daría un error de que hay duplicidad en el campo (o columna) autoincremental.
Por último, llenamos el objeto DataSet con los datos del DataAdapter, el segundo
parámetro es el nombre que le vamos a dar a la tabla virtual (la que se crea en memoria), si
no le damos un nombre a esa tabla virtual del DataSet, se asignará de forma
predeterminada con el nombre Table. Es conveniente asignar un nombre, ya que un objeto
DataSet permite tener en memoria distintos datos, de la misma o de otras tablas o
consultas. Ese nombre será el que usaremos para acceder a esos datos en memoria, ya que
todos los accesos al contenido del DataSet, como he comentado antes, se realizan de forma
desconectada, es decir sin relación ninguna con la base de datos física.
Los nombres de las tablas de una base de datos de SQL Server
Vamos a crear una función que devuelva una matriz (o array) del tipo String, con los
nombres de las tablas de la base de datos.
Friend Function NombresTablas(Optional ByVal nombreBase As String = "") As String()
'
Dim nomTablas() As String
Dim dataTable As New Data.DataTable()
Dim i As Integer
'
If dbConnection Is Nothing Then
dbConnection = New Data.SqlClient.SqlConnection(CadenaConexion)
End If
If dbConnection.State <> ConnectionState.Open Then
dbConnection.Open()
End If
'
Dim schemaDA As New Data.SqlClient.SqlDataAdapter( _
"SELECT * FROM INFORMATION_SCHEMA.TABLES " & _
"WHERE TABLE_TYPE = 'BASE TABLE' " & _
"ORDER BY TABLE_TYPE", _
dbConnection)
'
schemaDA.Fill(dataTable)
i = dataTable.Rows.Count - 1
If i > -1 Then
ReDim nomTablas(i)
For i = 0 To dataTable.Rows.Count - 1
nomTablas(i) = dataTable.Rows(i).Item("TABLE_NAME").ToString()
Next
End If
'
Return nomTablas
End Function
Antes de llamar a esta función tendremos que tener asignada la cadena de conexión o,
mejor aún, creada la conexión a la base de datos. Eso es lo que se hace en las primeras
líneas, si el objeto del tipo Connection no está creado, se crea un nuevo objeto, usando la
cadena de conexión. En caso de que esté creado el objeto, se comprueba si está abierta
dicha conexión, de no ser así, se abre.
A continuación asignamos un objeto del tipo DataTable con el "esquema" de las tablas
contenidas en la base de datos a la que apunta el objeto Connection.
Para conseguir los nombres de las tablas, buscamos las tablas del tipo "BASE TABLE".
Recorremos el contenido del objeto DataTable y accedemos a cada una de las filas cuyo
elemento contenga la cadena "TABLE_NAME", el cual nos dará el nombre de cada una de
las tablas. Ese nombre lo asignamos a cada uno de los elementos del array que estamos
usando de forma interna, el cual será el que la función devuelva.
Los nombres de los campos (o columnas) de una tabla
Para saber los nombres de los campos o columnas de una tabla, usaremos el contenido del
objeto DataSet que hace referencia a la tabla que hemos cargado mediante el
DataAdapter, aunque también podría servirnos para acceder a cualquier tabla virtual
contenida en el DataSet.
También vamos a crear una función que devuelva una matriz del tipo String:
Friend Function NombresColumnas() As String()
Dim columna As Data.DataColumn
Dim i, j As Integer
Dim nomCol() As String
'
j = dbDataSet.Tables(NombreTabla).Columns.Count - 1
ReDim nomCol(j)
For i = 0 To j
columna = dbDataSet.Tables(NombreTabla).Columns(i)
nomCol(i) = columna.ColumnName
Next
Return nomCol
End Function
Creo que el código es bastante auto-explicativo y no necesita más aclaración.
Asignar la cabecera de un control ListView con los nombres de las columnas o campos de una tabla
Para terminar con el código del módulo ADONETUtil, vamos a ver unos métodos que
usaremos para asignar las columnas (o cabecera) de un ListView con los nombres de las
columnas o campos de la tabla que vamos a utilizar.
El método se llama AsignarCabeceraLista y tendrá dos implementaciones, una indicando
sólo el nombre del ListView y la otra en la que además se indicará un control ComboBox
en el cual se asignarán también esos nombres de las columnas de la tabla.
Friend Sub AsignarCabeceraLista(ByVal ListView1 As ListView)
Dim columna As Data.DataColumn
Dim i, j As Integer
'
With ListView1
.View = View.Details
.FullRowSelect = True
.GridLines = True
.LabelEdit = False
.HideSelection = False
.Columns.Clear()
End With
'
Dim lasColumnas() As String
lasColumnas = NombresColumnas(CadenaConexion, CadenaSelect)
'
If Not lasColumnas Is Nothing Then
For i = 0 To lasColumnas.Length - 1
ListView1.Columns.Add(lasColumnas(i), 100, HorizontalAlignment.Left)
Next
End If
'
End Sub
Friend Sub AsignarCabeceraLista(ByVal ListView1 As ListView, _
ByVal cboCampos As ComboBox)
Dim i As Integer
'
AsignarCabeceraLista(ListView1)
cboCampos.Items.Clear()
For i = 0 To ListView1.Columns.Count - 1
cboCampos.Items.Add(ListView1.Columns(i).Text)
Next
'
If cboCampos.Items.Count > 0 Then
cboCampos.SelectedIndex = 0
End If
End Sub
Creo que tampoco necesita explicación, ya que lo único que se hace es llamar a la función
NombresColumnas y el contenido de ese array es el que se asigna a la cabecera del
ListView que se ha indicado en el parámetro.
En cuanto a la segunda implementación, se asigna al control ComboBox pasado como
parámetro esos mismos nombres.
Cuando veamos el código de los formularios, sabremos cuando usar una u otra versión de
este método.
Llenar un ListView con el contenido de una tabla
El siguiente método del módulo ADONETUtil rellenará un control ListView con los datos
de la tabla cargada en el objeto DataSet.
Friend Sub LLenarLista(ByVal unListView As ListView)
Dim i As Integer
Dim lwItem As ListViewItem
Dim fila As Data.DataRow
'
unListView.Items.Clear()
'
For Each fila In dbDataSet.Tables(NombreTabla).Rows
For i = 0 To unListView.Columns.Count - 1
If i = 0 Then
lwItem = unListView.Items.Add(fila(i).ToString)
lwItem.Tag = fila
Else
lwItem.SubItems.Add(fila(i).ToString)
End If
Next
Next
End Sub
El código es también bastante simple, sólo quiero aclarar un detalle: La asignación del
objeto fila al TAG del elemento del ListView.
Realmente no es necesario, pero yo lo utilizo esa fila para acceder a cada uno de los
registros de la tabla, ya que al modificar los datos, sólo los reflejaremos en el contenido del
ListView y de esa forma sabremos a que fila estamos accediendo. Cuando actualicemos los
datos, usaremos el objeto que hemos guardado en la propiedad Tag del objeto
ListViewItem, y ese mismo objeto será el que usaremos para eliminar una fila del DataSet.
El formulario principal
Este es el aspecto del formulario principal (Form1) en tiempo de diseño:
El formulario principal en tiempo de diseño
Este formulario permitirá que se arrastre una base de datos y ese nombre se asignará a la
caja de textos del nombre de la base de datos. Los controles tienen asignados los valores de
la propiedad Anchor para que se ajusten al tamaño que el usuario quiera darle al
formulario, esos detalles podremos verlo en el código completo, ya que aquí sólo mostraré
la parte que realmente interesa, es decir lo que está relacionado con el acceso a la base de
datos.
Empecemos por el código del botón "Mostrar tablas" y el evento producido cuando se
selecciona una tabla del ComboBox:
Private Sub btnAbrirBase_Click( _
ByVal sender As Object, ByVal e As EventArgs) _
Handles btnAbrirBase.Click
'
Dim nomTablas() As String
Dim i As Integer
'
nomTablas = NombresTablas(txtNombreBase.Text)
cboTablas.Items.Clear()
If Not nomTablas Is Nothing Then
For i = 0 To nomTablas.Length - 1
cboTablas.Items.Add(nomTablas(i))
Next
End If
If cboTablas.Items.Count > 0 Then
cboTablas.SelectedIndex = 0
End If
'
End Sub
Private Sub cboTablas_SelectedIndexChanged( _
ByVal sender As Object, ByVal e As EventArgs) _
Handles cboTablas.SelectedIndexChanged
txtSelect.Text = "SELECT * FROM " & cboTablas.Text
'
'' Si se quieren mostrar individualmente los nombres de los campos
'Dim lasColumnas() As String
'Dim s As String, i As Integer
''
'CadenaSelect = txtSelect.Text
'lasColumnas = NombresColumnas(CadenaConexion, CadenaSelect)
'For i = 0 To lasColumnas.Length - 1
' s &= lasColumnas(i) & ", "
'Next
'' Quitar la última coma
'i = s.LastIndexOf(", ")
's = s.Substring(0, i)
's = "SELECT " & s & " FROM " & cboTablas.Text
'txtSelect.Text = s
End Sub
El primer procedimiento intercepta la pulsación en el botón y asigna los nombres de las
tablas en el combo.
El segundo, simplemente crea la cadena SQL que se usará para acceder a dicha tabla.
El código que está comentado sirve para mostrar los nombres de los campos o columnas de
forma individual.
Cuando pulsamos en el botón "Mostrar", se muestra el contenido de la tabla indicada,
información que se obtiene del DataSet que contiene los datos en memoria. Aunque, el
código mostrado, realmente refresca esa información, esto lo he hecho así para que al
volver de modificar los datos, se pueda comprobar que los datos realmente se han guardado
en la base de datos.
Private Sub btnMostrar_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnMostrar.Click
'
With ListView1
.View = View.Details
.FullRowSelect = True
.GridLines = True
.LabelEdit = False
.HideSelection = False
.Columns.Clear()
End With
'
' Volver a reconectar para actualizar los datos desde la base
If Not dbConnection Is Nothing Then
dbConnection.Close()
End If
Conectar(txtNombreBase.Text, txtSelect.Text)
'
AsignarCabeceraLista(ListView1)
LLenarLista(ListView1)
End Sub
Como podemos comprobar, aquí se llaman a los métodos del módulo ADONETUtil, por
tanto al principio del código del formulario debemos hacer la importación del espacio de
nombres de ese módulo para no tener que especificarlo cada vez que queramos acceder a
cualquiera de los procedimientos o variables en el declarado:
' Importamos el módulo con las declaraciones de los objetos a usar
Imports ADONET_SQL.ADONETUtil
ADONET_SQL es el nombre del "espacio de nombres" (Namespace) de este proyecto.
Para acabar con el código de este formulario, veamos los eventos que se producen al
cargarse el formulario (Load) y al cerrarse (Closing), además del evento producido al
pulsar en el botón "Mostrar", el cual mostrará el formulario en el que se editan los datos de
la tabla indicada.
Private Sub Form1_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles MyBase.Load
Me.txtNombreBase.Text = "pubs"
Me.txtSelect.Text = "SELECT * FROM authors"
'
ArchivoDatos = txtNombreBase.Text
CadenaConexion = "data source=GUILLEACER\NETSDK;" & _
"initial catalog=" & ArchivoDatos & ";" & _
"integrated security=SSPI;persist security info=True;" & _
"workstation id=GUILLEACER;packet size=4096"
'
With ListView1
.View = View.Details
.FullRowSelect = True
.GridLines = True
.LabelEdit = False
End With
'
cboTablas.Text = ""
End Sub
Private Sub Form1_Closing(ByVal sender As Object, _
ByVal e As System.ComponentModel.CancelEventArgs) _
Handles MyBase.Closing
' Cerrar la conexión
Try
If dbConnection.State = ConnectionState.Open Then
dbConnection.Close()
End If
Catch
End Try
End Sub
Private Sub btnModificar_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnModificar.Click
Dim f2 As New Form2()
With f2
.DataSource = txtNombreBase.Text
.CommandString = txtSelect.Text
.ShowDialog()
End With
btnMostrar_Click(btnMostrar, e)
End Sub
En el evento Load, asignamos los valores iniciales, en el evento Closing, comprobamos si
tenemos la conexión abierta y de ser así la cerramos, debido a que puede ser que se cierre el
formulario sin necesidad de haber creado dicho objeto, interceptamos el error que se
pudiera producir.
Por otro lado, cuando pulsamos en el botón Modificar, creamos una nueva instancia del
formulario en el que modificaremos la información y asignamos los valores de la base de
datos y la cadena SQL que usaremos para conectar, esto lo hago así por si se pulsa en dicho
botón sin haber creado la conexión.
El formulario de edición de datos
Para terminar con este ejemplo de acceso a datos usando ADO.NET, veamos el formulario
que usaremos para modificar la información de la base de datos.
El aspecto del formulario (FORM2) será el mostrado en la siguiente imagen:
El formulario de introducción de datos
En este formulario, los controles también están "anclados" para que se adapten al tamaño
que el usuario quiera darle al formulario.
Empecemos por las variables o propiedades que este formulario expone al mundo externo:
' Importamos el módulo con las declaraciones de los objetos a usar
Imports ADONET_SQL.ADONETUtil
Public Class Form2
Inherits System.Windows.Forms.Form
Friend DataSource As String
Friend CommandString As String
'
Private lwItemActual As ListViewItem
También usamos el Imports para poder usar los procedimientos del módulo ADONETUtil
y declaramos dos propiedades: DataSource y CommandString, las cuales usaremos para
acceder a la base de datos.
La variable lwItemActual hará referencia al elemento del ListView que esté actualmente
seleccionado.
En el evento Load del formulario, se asignarán algunos valores por defecto y se mostrará el
contenido de la tabla indicada en el ListView:
Private Sub Form2_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles MyBase.Load
Me.txtCampo1.Text = ""
'
' para usar este formulario como formulario inicial
If DataSource = "" Then
DataSource = "pubs"
End If
If CommandString = "" Then
CommandString = "SELECT * FROM authors"
End If
'
lblInfo.Text = _
"Base: " & NombreBase(DataSource) & ", Select: " & CommandString
'
If Not dbConnection Is Nothing Then
dbConnection.Close()
End If
Conectar(DataSource, CommandString)
'
AsignarCabeceraLista(ListView1, cboCampos)
LLenarLista(ListView1)
'
Me.AcceptButton = btnAsignar
End Sub
Cuando seleccionamos un nuevo elemento del ListView, se asigna la variable que contiene
el elemento actual y se muestra la información o datos de dicha fila.
Private Sub ListView1_SelectedIndexChanged(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles ListView1.SelectedIndexChanged
Try
lwItemActual = ListView1.SelectedItems(0)
Catch
End Try
End Sub
Private Sub ListView1_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles ListView1.Click, _
cboCampos.SelectedIndexChanged
Try
lwItemActual = ListView1.SelectedItems(0)
MostrarCampo()
Catch
End Try
End Sub
Como podemos comprobar, el procedimiento ListView1_Click realmente intercepta dos
eventos, el evento Click del ListView y el evento SelectedIndexChanged del Combo, de
forma que se muestre la información del campo seleccionado en el ComboBox. De eso se
encarga el procedimiento MostrarCampo:
Private Sub MostrarCampo()
Dim i As Integer
'
Try
i = cboCampos.SelectedIndex
If i = 0 Then
txtCampo1.Text = lwItemActual.Text
ElseIf i > -1 Then
txtCampo1.Text = lwItemActual.SubItems(i).Text
End If
Catch
End Try
End Sub
Este procedimiento simplemente muestra el contenido del campo que está seleccionado en
el control ComboBox.
Asignar los datos
Cuando pulsamos en el botón Asignar, el cual hemos asignado como botón "Aceptar" del
formulario, es decir el que tomará el foco cuando pulsemos la tecla Intro, se asignarán los
cambios realizados al campo (o columna) que estamos editando:
Private Sub AsignarCampo(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnAsignar.Click
' Asignar al ListView el campo modificado
Dim i As Integer
'
i = cboCampos.SelectedIndex
If i = 0 Then
lwItemActual.Text = txtCampo1.Text
ElseIf i > -1 Then
lwItemActual.SubItems(i).Text = txtCampo1.Text
End If
End Sub
Eliminar una fila
Cuando pulsamos en el botón Eliminar, borramos la fila seleccionada del ListView y
también esa misma fila del DataSet, y como comenté anteriormente, en la propiedad Tag
del elemento del ListView tenemos una referencia a la fila de datos, por tanto usamos ese
objeto para eliminar la fila de la colección Rows del objeto DataSet, ya que el método
Remove de la colección Rows acepta como parámetro un objeto del tipo DataRow:
Private Sub btnEliminar_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnEliminar.Click
' Eliminar la fila indicada
Dim fila As Data.DataRow
'
fila = CType(ListView1.SelectedItems(0).Tag, Data.DataRow)
dbDataSet.Tables(NombreTabla).Rows.Remove(fila)
ListView1.Items.Remove(ListView1.SelectedItems(0))
End Sub
Crear una nueva fila (o registro)
Para crear un nuevo registro (o fila), tendremos que asignar unos valores nulos o por
defecto a una nueva fila creada en la memoria, después esa fila la añadiremos a la tabla que
mantenemos en el DataSet.
Debido a que algunos campos no permiten valores nulos, tendremos que tener ese detalle
en cuenta y de ser así, asignaremos un valor adecuado al tipo de datos de cada una de las
columnas (o campos) del registro que hemos creado, esto lo conseguimos comprobando el
tipo de datos de cada una de las columnas de la nueva fila. Hay que tener en cuenta que los
tipos de datos se guardan usando el que se define en .NET Framework, no los tipos que
utiliza Visual Basic, por tanto, para saber si el tipo de una columna es del tipo Integer,
tendremos que usar System.Int32, de todas formas, para saber el tipo de dato, (que lo da la
propiedad DataType del objeto DataColumn), he utilizado la conversión a cadena
generada por ToString, por lo que dicho tipo se convierte en el formato "System.Tipo",
veamos el código para aclarar todo este lío:
Private Sub btnNuevo_Click(ByVal sender As Object, _
ByVal e As EventArgs) _
Handles btnNuevo.Click
' Añadir una nueva fila (o registro)
Dim fila As Data.DataRow
Dim i As Integer
Dim lwItem As ListViewItem
Dim columna As Data.DataColumn
'
fila = dbDataSet.Tables(NombreTabla).NewRow
fila.BeginEdit()
For i = 0 To dbDataSet.Tables(NombreTabla).Columns.Count - 1
columna = dbDataSet.Tables(NombreTabla).Columns(i)
'Debug.WriteLine(columna.DataType.ToString)
If columna.AutoIncrement = False Then
Select Case columna.DataType.ToString
Case "System.String"
fila(i) = columna.ColumnName
Case "System.Boolean"
fila(i) = False
Case "System.Byte", "System.SByte"
fila(i) = CByte(0)
Case "System.Char"
fila(i) = " "c
Case "System.DateTime", "System.TimeSpam"
fila(i) = Now
Case "System.Decimal", "System.Double", "System.Single"
fila(i) = 0
Case Else
'Case "System.Int32","System.UInt32"
' fila(i) = 0
If columna.DataType.ToString.IndexOf("System.Int") > -1 Then
fila(i) = 0
ElseIf columna.DataType.ToString.IndexOf("System.UInt") > -1 Then
fila(i) = 0
End If
End Select
End If
Next
fila.EndEdit()
' Añadir la fila a la tabla
dbDataSet.Tables(NombreTabla).Rows.Add(fila)
'
' Mostrar la nueva fila en el ListView
For i = 0 To ListView1.Columns.Count - 1
If i = 0 Then
lwItem = ListView1.Items.Add(fila(i).ToString)
lwItem.Tag = fila
Else
lwItem.SubItems.Add(fila(i).ToString)
End If
Next
'
End Sub
Lo que en este evento hacemos es crear una nueva fila mediante el método NewRow,
asignamos los campos (o columnas) de dicha fila y la añadimos a la colección Rows de la
tabla. Hay que tener en cuenta que al crear una nueva fila con NewRow no se añade a la
colección de filas (o registros), simplemente se devuelve un objeto que está preparado para
que se le asignen los datos correspondientes. Antes de asignar cada una de las columnas,
comprobamos si dicha columna está marcada como autoincremental, de ser así, no
asignamos nada, ya que es el propio DataAdapter el que se encarga de asignar el valor de
dicha columna.
En este punto quiero hacer una aclaración, debido a que los datos los estamos asignando a
un objeto que mantiene la información en la memoria, si existen varias aplicaciones que
acceden a la misma base de datos y cada una de ellas crea nuevas filas, el valor asignado al
campo (o columna) AutoIncrement puede que no sea el que definitivamente tenga en la
base de datos. Por tanto, debemos tener esto presente si el valor asignado a esa columna lo
utilizamos para otros menesteres.
Una vez que hemos añadido la nueva fila a la tabla, asignamos el contenido de la misma al
ListView y también asignamos a la propiedad Tag una referencia a dicha fila.
Guardar la información en la base de datos
Por último vamos a ver cómo pasar la información mantenida en la memoria a la base de
datos, con idea de que los cambios realizados se queden guardados permanentemente.
Esto lo hacemos cuando el usuario pulsa en el botón de "Actualizar Base" y el código
usado es el siguiente:
Private Sub btnActualizarBase_Click(ByVal sender As Object, _
ByVal e As EventArgs) _
Handles btnActualizarBase.Click
' Actualizar la base de datos con los cambios realizados
Dim fila As Data.DataRow
Dim i, j As Integer
Dim lwItem As ListViewItem
Dim columna As Data.DataColumn
'
lblInfo.Tag = lblInfo.Text
lblInfo.Text = "Actualizando los datos..."
lblInfo.Refresh()
Try
For i = 0 To ListView1.Items.Count - 1
lwItem = ListView1.Items(i)
fila = CType(ListView1.Items(i).Tag, Data.DataRow)
fila.BeginEdit()
j = 0
For Each columna In dbDataSet.Tables(NombreTabla).Columns
If j = 0 Then
If columna.AutoIncrement = False Then
fila(j) = lwItem.Text
End If
Else
If columna.AutoIncrement = False Then
fila(columna.ColumnName) = lwItem.SubItems(j).Text
End If
End If
'
j += 1
Next
fila.EndEdit()
Next
'
'
dbDataAdapter.Update(dbDataSet, NombreTabla)
dbDataSet.AcceptChanges()
'
'
lblInfo.Text = CStr(lblInfo.Tag)
Catch errActualizar As Exception
lblInfo.Text = errActualizar.Message
MsgBox(errActualizar.Message)
End Try
End Sub
En este procedimiento actualizamos la información de cada una de las filas, para ello
usamos el objeto almacenado en la propiedad Tag de cada uno de los elementos del
ListView que como recordarás era en realidad una referencia a cada una de las filas de la
tabla, (realmente un objeto del tipo DataRow). Recorremos cada una de las columnas y
asignamos sólo los datos si no es una columna del tipo AutoIncrement.
La llamada a los métodos BeginEdit y EndEdit de cada fila es para que no se produzcan
los eventos asociados a un objeto de este tipo, no son realmente necesarios para poder
cambiar los contenidos de las columnas.
Una vez que hemos asignado todos los datos del ListView, llamamos al método Update
del DataAdapter, este método es el que realmente hace que los datos se guarden
físicamente en la base de datos.
Después llamamos al método AcceptChanges del objeto DataSet para que "sepa" que
hemos aceptado la nueva información y marque la información de forma que sean iguales a
los datos que tiene la base de datos real.
Como habrás podido comprobar, si lo comparas con el ejemplo de Access, el código es
prácticamente igual, sólo cambia la "procedencia" de algunos objetos, (espacios de
nombres), así como el nombre de los mismos, pero en general el código no tiene apenas
cambios.
En otra ocasión, espero que no se haga tanto de rogar como esta con respecto a la de
Access, veremos un código aún más genérico para acceder tanto a bases de datos de Access
como de SQL Server; si veo que tardo mucho en "depurar" ese código, lo publicaré como
esté y ya habrá tiempo de actualizarlo o mejorarlo.
Nos vemos.
Guillermo
Si quieres bajarte el código completo de este ejemplo, usa este link: ADONETSQL.zip 14.9
KB
Saludos bueno el problema que tengo es que estoy haciendo un sistema para entregar solo que con base de datos ya lo habia hecho pero de una forma sencilla,ahora lo que quiero es que se conecte a la base de datos, cuando lo lea primero verifique el usuario si el usuario existe se va a ir a otra condicion que es el del password y dentro del password llamo el otro formulario que es menu dejo codigo para que me digan en que me equivoco lo que pasa es que a la hora de que lea el password en la lectura me da el daot de la caja de texto y no de la base de datos, y con el and en el comando si no esta bien cualquiera de los dos pues no entra a la primera condicioncomo le puedo hacer para solo conectarme con el nombre de usuario a la bd y que de ahi pueda leer los dos datos y pueda ingresar al menu
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnIngresar.ClickDim cnx As SqlConnection = New SqlConnection("Data Source=YOP\SQLEXPRESS;Initial Catalog=otra;Integrated Security=True")Dim cmd As New SqlCommand("select * from Usuarios where @Usuario=usuario and @password=Password ", cnx)'con estos dos si no cumple uno no entro igual ya sabe pero para que lo identifiquecmd.CommandType = CommandType.Textcmd.Parameters.Add(New SqlParameter("@usuario", TxtUsuario.Text))cmd.Parameters.Add(New SqlParameter("@Password", TxtContraseña.Text))cnx.Open()Dim leer As SqlDataReader = cmd.ExecuteReaderIf leer.Read() = True Then ' si una de las anteririores no se cumple no entra If TxtUsuario.Text = leer(0).ToString Then 'este campo si lo lee bien
If TxtContraseña.Text = leer(1).ToString Then 'este es el que me causa problemas
FrMenu.Show()Me.Hide()
ElseMsgBox("no puedes ingresar contraseña incorrecta")
TxtUsuario.Clear()TxtContraseña.Clear()TxtUsuario.Focus()End If
ElseMsgBox("no puedes ingresar usuario incorrecto")
TxtUsuario.Clear()TxtContraseña.Clear()
TxtUsuario.Focus()End IfEnd IfEnd Sub