14 marzo 2007

El ADO Contraataca: inicializando mis objetos y metiéndoselas a la tabla

Ahora que ya comenzamos a hacer un sistema que usa VB 6.0 y ADO para hacer un programita simple, vamos a dar el siguiente paso. En mi mensaje anterior, hablé (bueno, escribí) acerca de la manera de agregar la referencia a los objetos ADO (ActiveX Data Objects), declarar objetos globales de tipo ADODB.Connection, ADODB.Command y ADODB.Recordset, y uno que otro detallito más (si no lo leíste, lo puedes leer aquí).

Hasta allí empezaba la cosa bien, pero nos quedamos a medias (bueno, tampoco es mi intención abarcar todo lo faltante en este mensajito). Ahora voy a hacer dos cosas: voy a inicializar mis objetos ADO desde la subrutina Form_Load() de la primera ventana que abre mi aplicación y voy a programar un botón que da de alta un registro en una tabla. Si quieres el código completo de lo que va hasta ahorita (archivos de formas, de proyecto, íconos y una que otra chuchería más), lo puedes bajar aquí.

Primero, lo primero. El primer form (que yo bauticé como frmPrincipal en lugar de aburrido Form1 que le pone VB por default) tiene una serie de botones que abrirán otras ventanas que llevarán a cabo todo lo que quiere hacer doña Amalia en su taquería. Esta ventana, en mi ambiente de diseño de VB 6.0, se ve así:


Intenté hacerlo lo más sencillo pensando en que los que lo usarán son trabajadores de una taquería, con botones grandes que sean fáciles y rápidos de apretar que tienen iconos. Además tienen ToolTipText, una propiedad de casi todos los controles, para que aparezcan mensajitos explicativos de cada uno y son accesibles presionando la tecla ALT más el de la letra subrayada que tiene cada botón, la cual la asigné anteponiendo el ampersand (&) antes de la letra subrayada.

Dejando esto a un lado, vámonos al código. Como esta es la primera ventana que se carga a la memoria, en cuanto se cargue quiero que inicialice mis objetos ADO. Para esto, escribí este código en la subrutina Form_Load de esta ventana. El código es este:


Con el Set creo un nuevo objeto (lo estoy usando tanto para el Connection, el Command y el Recordset). El ConnectionString es una propiedad que tiene el objeto ADODB.Connection para definir la base de datos a la que se va a conectar y quién es el proveedor del servicio. En nuestro caso, estamos usando una base de datos hecha en Access que se llama Tacos.mdb. Al rato subo un mensaje donde explico mejor como se usa, pero si vas a usar una base de datos de Access, copia el código tal cual. Si te fijas, uso la propiedad App.Path para determinar desde qué carpeta está ejecutándose el programa. El archivo Tacos.mdb lo voy a guardar en el mismo lugar del ejecutable y de esta manera, no importa donde se instale mi programa, va a poder encontrar mi base de datos.

Una vez usado el ConnectionString para decirle con quién conectarse (Data Source) y quién los va a conectar (Provider), abro la conexión (Open). Con esto termino de inicializar mi conexión y puedo usarlo al crear mi objeto Recordset. Después de crearlo (con el New), le digo que la conexión que va a usar es la que acabo de inicializar, en nuestro caso, se llama conConnection (con el ActiveConnection).

Al final estoy creando un objeto Recordset (con el New) y le estoy diciendo que todo el trabajo "pesado" (filtrar datos, unir registros, ordenar, etc.) lo haga en el servidor de la base de datos (CursorLocation=adUseServer). La otra opción, que no recomiendo, es decirle que todo el trabajo lo hace la máquina donde está trabajando el usuario (CursorLocation=adUseClient). No lo recomiendo porque, en casi todas las ocasiones, el servidor de la base de datos es una maquinotototota choncha que tiene mayor capacidad de procesamiento que la PC de un mero mortal.

En fin, con eso termino la inicializadera. Ahora voy a proseguir a insertar un registro desde mi aplicación VB 6.0 por medio del objeto ADODB.Command. Esto lo voy a hacer en la ventana de Proveedores (frmProveedor) que se ve así en la vista de diseño:

Bueno, todavía no decido en un icono chuvidubis para el botón Agregar, pero luego que halle uno, se los paso. Pero eso es lo de menos, ahora nos interesa lo que se puede hacer con ese botón. Por esto, el código relacionado a este botón, que se ejecuta cada vez que un usuario de click sobre él, es este:


¿Se ve medio confuso? ¡No te apures que no lo es tanto! Sólo que vayámonos poco a poco. Para empezar, si no escribe nada en la caja de texto donde va el nombre (que yo nombré txtNombre), le marca error y sitúa el cursor en esa caja para que el usuario le teclee el nombre bien. Había puesto una condición que simplemente viera si no habían escrito nada (o sea, If txtNombre="" Then), pero un alumno, el buen Trank, me sugirió que validara también si da un espacio, cosa que sería válido si hubiera usado el If original. Luego entonces, de manera rauda y veloz, usé la función Trim para eliminar todos los espacios en blanco antes y después de una cadena. Si solo dió puros espacios, de todos modos marca error de nombre inválido.

Si este no es el caso, supongo quetodos los otros campos son opcionales. Ahora sí va lo único que aparenta ser difícil, pero que una vez que le agarres la onda, vas a ver que es sencillo. Todos los comandos SQL que le vamos a enviar a nuestra base de datos por medio de la conexión es usando la propiedad CommandText del objeto ADODB.Command. A esta propiedad se le asigna una cadena que contenga una instrucción SQL válida. Una vez aclarado esto, pasemos a ver que instrucción SQL necesito usar.

La instrucción para insertar un registro en una tabla en SQL es INSERT INTO, cuya sintáxis es así:

INSERT INTO tabla (lista de campos) VALUES (lista de valores)

Por ejemplo, en mi tabla, supongamos que quiero dar de alta a un proveedor. Entonces podría escribir la siguiente instrucción SQL:

INSERT INTO Proveedor (Nombre, Tel, Fax, Email, Web) VALUES ("Textiles Alfonso", "3635-3990", "8111-1112", "http://www.telasponcho.com")

Esto es tal cual lo que hago en mi código, con una pequeña diferencia. En mi programa, tanto como "Textiles Alfonso", "3635-3990", "8111-1112" y "http://www.telasponcho.com" están guardados en txtNombre, txtTel, txtFax, txtEmail y txtWeb, respectivamente. No puedo escribir esta instrucción:

INSERT INTO Proveedor (Nombre, Tel, Fax, Email, Web) VALUES ("txtNombre, "txtTel", "txtFax", "txtEmail", "txtWeb")

porque no tengo un cliente que se llame txtNombre ni su teléfono es txtTel. Lo que quiero es lo que está almacenado en txtNombre, txtTel, etc.

No hay que perder de vista que la propiedad CommandText es de tipo cadena, por lo que voy a armar una cadena de texto que tenga la instrucción tal y como quedar. Un operador básico para armar cadenas es el ampersand (&) el cual une (dicho elegantemente "concatena") dos cadenas para formar una sola. Y si después del ampersand dejo un espacio y escribo un guión bajo (_) quiere decir que puedo seguir concatenando la cadena que viene en el siguiente renglón. Por ejemplo, "Tony " & " Valderrama" sería igual a "Tony Valderrama". Usando esto, puedo armar mi cadena de la siguiente forma: cmdCommand.CommandText = "INSERT INTO Proveedor" & _ " (Nombre, Tel, Fax," & _ " Email, Web) VALUES ('" & _ txtNombre

almacenaría la cadena

INSERT INTO Proveedor, Tel, Fax, Email, Web) VALUES ('Textiles Alfonso

Fíjate que alrededor de valores que son texto le estoy poniendo apóstrofes (') para delimitar cadenas DE LA INSTRUCCIÓN SQL. Usa las comillas (") para delimitar cadenas de VISUAL BASIC.

Siguiendo con nuestro ejemplo anterior, todavía no está cerca de estar terminada. Siguiendo con el merequetengue de ir explicando paso a paso esa instrucción, le agregaría al final un & "','" de la siguiente manera:

cmdCommand.CommandText = "INSERT INTO Proveedor " & _ "(Nombre, Tel, Fax," & _ " Email, Web) VALUES ('" & _ txtNombre & "','"

Esto me almacenaría en la cadena esto:

INSERT INTO Proveedor, Tel, Fax, Email, Web) VALUES ('Textiles Alfonso','

¿Ves? Cierro el texto Textiles Alfonso con apóstrofes para indicar que es un tipo de dato cadena o texto y no se haga bolas. Recuerda que los números no llevan.

Siguiendo esta lógica, podrás imaginar que esta instrucción completa

cmdCommand.CommandText = "INSERT INTO Proveedor " & _ "(Nombre, Tel, Fax," & " Email, Web) VALUES ('" & _ txtNombre & "','" & txtTel & "','" & _ txtFax & "','" & txtEmail & "','" & txtWeb & "')"

Nos devolvería esta cadena:

INSERT INTO Proveedor (Nombre, Tel, Fax, Email, Web) VALUES ('Textiles Alfonso', '3635-3990', '8111-1112', 'http://www.telasponcho.com')

¡Listo! Allí está una instrucción SQL correcta almacenada en la propiedad de mi objeto Command. Ahora le tengo que decir que ejecute esa acción mediante el método Execute (cmdCommand.Execute) y todo está listo.

Todavía falta mucho por hacer y aprender, pero por lo menos están los primeros pasos. ¡Nos vemos en la próxima!

9 comentarios:

MarketMaster dijo...

Hola Tony, antes que todo agradecerte por dicho esfuerzo y vale la pena ya que mucho de mis compañeros y yo utilizamos y aprendemos con tus tutoriales. Muchas gracias..

Ahora tengo una pequeña duda, cual es el Valor o Value para un campo de texto, aver lo que pasa es que quiero que el usuario ingrese estos datos: Rut,Nombre,Apellidos,Comentarios. Y este es el codigo que ocupo.

Comm.CommandText = "INSERT INTO PROFESORES (Rut,Nombre,Apellidos,Comentarios) VALUES('Rut','dsds','cxcx','dsdsd')"


El Valor de Rut deberia ser numerico y el resto que le debo agregar para que me capturen lo que el usuario escribio en :

txtNombre
txtApellidos
txtComentarios

Agradecieria tu ayuda nuevamente.. ;)

Tony Valderrama dijo...

Lo que tienes que hacer es armar una cadena, concatenando los valores que quieres.

Yo escribiría algo así (tu lo revisas a ver si aplica a tu problema particular):

Comm.CommandText="INSERT INTO PROFESORES (Rut,Nombre,Apellidos,Comentarios) VALUES (" & txtRut & ",'" & txtNombre & "','" & txtApellidos & "','" & txtComentarios & "')"

Estoy suponiendo que existe txtRut que tiene el valor numérico.

Espero que esto resuelva tu duda y te sirva. ¡Saludos!

Anónimo dijo...

Voy como avión gracias a ti tony.

Pero se me presento un problema que nadie me puede solucionar, respecto a lo siguente.

Tengo Datos en mi BD especificamente un codigo, entonces el problema esta cuando el cliente ingresa el mismo codigo, se me cae el programa, no se como validar, lo hago asi:

If (txtcodigo.text = textcodigo.text)
"msje repetido"
else
"hecho"
end if


pero asi siempre me va a dar una respuesta repetido.

¿Como comparo un dato que ingresa el usuario con un dato que tengo en mi base de datos?

Me dijieron que con un recordset, pero por lo que veo OLEDB no trabaja con recordset o el visual 2008...

Me ayudas?..


Gracias.

Tony Valderrama dijo...

En ADO escribirías algo así

if txtcodigo.text = tabla!Campo then
"mensaje repetido"
else
"lo que vayas a hacer"
endif

Suponiendo que tabla es un objeto de tipo ADODB.Recordset y Campo es el nombre del campo de la tabla.

Espero que esto te sea de utilidad. ¡Saludos!

Anónimo dijo...

Lamentablemente no me sale la opcion de recordset en el visual 2008.

Este es mi codigo.

If Not IsNumeric(txtCodigo.Text) Then
MsgBox("Ingrese un valor númerico para el codigo")
Else

Dim strConexion As String = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=bd.mdb"
Dim Conex As New OleDb.OleDbConnection
Dim Comm As New OleDb.OleDbCommand
Conex.ConnectionString = strConexion
Comm.Connection = Conex
Comm.CommandText = "INSERT INTO CODIGO (Codigo,Nombre,Apellidos,Comentarios) VALUES ('" & txtCodigo.Text & "','" & txtNombre.Text & "','" & txtApellidos.Text & "','" & rtxtComentarios.Text & "')"
Conex.Open()
Comm.ExecuteNonQuery()
Conex.Close()
If (txtCodigo.Text = '" & txtCodigo.Text & "') Then

MsgBox("Codigo Repetido")
Else

MsgBox("Resgistro Existoso" & Chr(13) & Chr(13) & "Debe reiniciar para activar los cambios", MsgBoxStyle.OkOnly, "Registro")
End If
End If

Tony Valderrama dijo...

Újule. Debo confesarte que todavía no soy gran experto en bases de datos con Visual Basic 2008.

Como verás en mi blog, apenas he hecho pininos en Visual Basic 2005, pero tengo idea de cómo hacerlo con ADO (es muy similar), pero no le he entrado con otras cosas.

Sin embargo hay algunos libros buenos sobre el uso de bases de datos en Visual Basic 2005/2008. Hace tiempo uséuno muy bueno que bajé de internet. Ahorita no lo tengo conmigo, pero deja lo busco y te digo cuál es y de dónde bajarlo, ¿sale?

¡Saludos!

Juan Jose Gutierrez Aldana dijo...

Hola Tony como estas? mira tengo un gran problema, necesito hacer una consulta para ver un ID y luego sumarle 1 mas ahora mi preguna es como guardo el resultado de una consulta en una variable en vb 2005...

asi tengo el cdo de consulta (hecho con tus guias de ADO)
comand.CommandText = "SELECT MAX('IOM')FROM IOM"
comand.Execute()
como guardo el resultado en una variable??? AYUDA POR FAVOR :S

Tony Valderrama dijo...

No lo he probado de esa manera, pero siempre que tienes un SELECT, lo tienes que abrir con un objeto tipo Recordset.

Aunque no lo he probado, yo intentaría algo así (suponiendo que mi objeto Recordset se llama tabla):

comand.CommandText = "SELECT MAX('IOM') AS MaxION FROM IOM"
tabla.Open comand,,adBatchLockOptimistic,adUseStatic
variable=tabla!MaxIOM
tabla.close

No sé si funciona, pero creo que por allí va la onda.

Por cierto, a lo mejor me equivoqué de orden del adBatchLockOptimistic y el adUseStatic. El Visual Basic te los sugiere en automático si es que todo está bien escrito.

Luego me comentas a ver si funcionó, ¿sale?

¡Saludos!

danieltango dijo...

Que tal amigo Tony. Te comento: Estoy teniendo problemas con el tema que estás tratando y la verdad que he buscado por todos lados y no he encontrado solución.
Espero veas este código y me puedas dar respuesta a mi problema.
Desde ya muchas gracias por tratar de ayudar a la gente a resolver sus problemas.
Este es el código que me preocupa:

Private Sub cmdGuarda_Click()

Dim IngresaCod As String
Set Base = New ADODB.Connection
AbrirBase
Set rst = New ADODB.Recordset
IngresaCodDador = "Select * from Voluntarios where NumVoluntario = " & frmGestionVoluntarios.txtModVoluntario(0).Text & "" _

"' And ApeVol LIKE '%" & frmGestionVoluntarios.txtModVoluntario(1).Text & "%'" _
"' And NomVol LIKE '%" & frmGestionVoluntarios.txtModVoluntario(2).Text & "%'" _
"' And FNacVol LIKE '%" & frmGestionVoluntarios.DTPFNac.Value & "%'" _
"' And TipoDocumento LIKE '%" & frmGestionVoluntarios.cmbTipoDoc.ListIndex & "%'" _
"' And NumDocumento LIKE '%" & frmGestionVoluntarios.txtModVoluntario(3).Text &"%'" _
"' And DomicilioParticular LIKE '%" & frmGestionVoluntarios.txtModVoluntario(4).Text &"%'" _
"' And TelefonoParticular LIKE '%" & frmGestionVoluntarios.txtModVoluntario(5).Text &"%'" _
"' And Celular LIKE '%" & frmGestionVoluntarios.txtModVoluntario(6).Text &"%'" _
"' And EMail LIKE '%" & frmGestionVoluntarios.txtModVoluntario(7).Text & "%'" _
"' And Profesion LIKE '%" & frmGestionVoluntarios.txtModVoluntario(8).Text & "%'"

Me marca esta primer línea: "' And ApeVol LIKE '%" &
y me dice: Error de compilación: Se esperaba: Número de línea o etiqueta o instrucción o fin de la instrucción
Bueno, espero puedas darme una mano. Desde ya muchas gracias!!

El Tony y sus ondas...

Related Posts Plugin for WordPress, Blogger...