Page 1 of 2

Ejemplo del uso del un recorset con xbrowse

PostPosted: Fri Feb 08, 2008 2:37 pm
by leandro
Amigos del foro tengan buen dia, alguien me puede indicar de casualidad como se usa un recorset, directamente con un xbrowse.

De antemano gracias

PostPosted: Sat Feb 16, 2008 2:10 am
by alex_cyr
pues mira yo use WBROWSE y para usar recordset tienes que definir el tipo de cursor correcto, definierle lo codigos de blocks de navegacion asi como definir una funcion skipper especial...

oLbx1:bLogicLen := { || oRecordSet:RecordCount }
oLbx1:bGoTop := { || oRecordSet:MoveFirst() }
oLbx1:bGoBottom := { || oRecordSet:MoveLast() }
oLbx1:bSkip := { | nSkip | Skipper( oRecordSet, nSkip ) }



STATIC FUNCTION SKIPPER( oRs, nSkip )

LOCAL nRec := oRs:AbsolutePosition

oRs:Move( nSkip )
IF oRs:EOF()
oRs:MoveLast()
endif
IF oRs:BOF()
oRs:MoveFirst()
ENDIF

RETURN oRs:AbsolutePosition - nRec


Debo aclararte que no lo he hecho funcionar al 100% ya que cuando me muevo hacia la derecha en el browse me hace un efecto "extraño"...

Ojala te sirva de algo.
Saludos.
Alex.

PostPosted: Sat Feb 16, 2008 6:02 pm
by Biel EA6DD
Code: Select all  Expand view
...
//oRs tiene el recordset ya creado.
oBrw := TXBrowse():New( oWnd )
oBrw:SetAdo(oRs)
oBrw:CreateFromCode()
oWnd:oClient:=oBrw
...

Tambien puedes consultar este otro hilo http://fivetechsoft.com/forums/viewtopic.php?t=8231

PostPosted: Sat Feb 16, 2008 6:52 pm
by MauroArevalo
Biel:

Se me ocurre una idea, te la voy a proponer a ver si te animas..

Porque no haces un manual como para niños de KINDER sobre como comenzar a utilizar ADO, yo leo tu BLOG y se que tu colaboras desinteresadamente a la comunidad de fivewineros.

Cuando yo aprendi clipper lo hice a punta de comprar libros y prácticar y repasar y practicar y repasar hasta que fui aprendiendo. Y creo que si tenemos un manual de KINDER y despues para PRIMARIA y asi sucesivamente iremos haciendo la transicion a ADO.

Lógico tu tiempo vale y por eso estaria dispuesto a pagar ($$ bueno Euros) por dicho manual. ¿Que te parece?; creo a que muchos nos serviria para dar ese salto.

Saludos

PostPosted: Sat Feb 16, 2008 7:13 pm
by Manuel Valdenebro
Mauricio,

El tema de ADO es bastante simple y realmente no es necesario un manual. En la red existe bastante información que es de donde (la mayoría) hemos ido aprendiendo.

http://www.w3schools.com/ado/default.asp

Pero si lo que se pretende es trabajar con una base de datos "seria" (cliente-servidor) tales como Oracle, MySql, SqlServer, etc. en mi opinión, habría que dividir el tema en tres pasos:

1) Lenguaje SQL (fundamental)
2) ADO
3) Temas específicos de cada base de datos (por ejemplo, Oracle tiene su propio lenguaje).

PostPosted: Sat Feb 16, 2008 10:13 pm
by MauroArevalo
Manuel:

Gracias

Y tienes toda la razón, es trabajar con base de datos cliente\servidor, lo que es no plantear bien la duda o pregunta.

Así como lo planteas es perfecto para iniciarse.

El primer punto no habriá necesidad porque hay bastante documentación, cursos, manuales, etc...de hecho ya hago pruebas con MYSQL desde la linea de comandos (crear, modificar, consultas, etc.)

El segundo ADO tambien pasa.

Entonces seria el tercer punto.

Temas específicos de cada base de datos (por ejemplo, Oracle tiene su propio lenguaje).

Dominando este tema podriamos tener nuestros sistemas en diferentes versiones atacando DBF, MYSQL, ORACLE, etc..


PD: ¿Manuel y al fín no viniste a Colombia el año pasado?, te teniamos una invitación a tomar puro cafecito colombiano.


Saludos,

PostPosted: Sun Feb 17, 2008 1:36 am
by horacio
El problema de las BBDD cliente - servidor no es como atacarlas desde nuestros programas mediante Ado ( en el foro hay bastante documentación con respecto a este tema ). El mayor problema es cambiar la visión que nosotros tenemos con respecto de las bases de datos que hemos venido manejando ( dbf ). Hasta ahora la lógica la manejabamos nosotros, desde nuestras aplicaciones pero cuando trabajamos sobre esta tecnología la lógica es manejada por el servidor mediante store procedures ( procedimientos almacenados ) y triggers ( disparadores ). y para trabajar con estas herramientas es necesario aprender el lenguaje de la BBDD. Creer que solamente con una cadena de conexión y el comando SELECT tenemos todo resuelto es una ingenuidad. Si realmente queremos que nuestros sistemas sean eficientes debemos cambiar la mentalidad ( y estudiar bastante ). Yo he hecho pruebas con 200 o 300 registros y el rendimiento no ha variado significativamene con respecto a una base distribuida ( dbf ) pero hablar de más de 3.000.000 de registros y conectarnos en forma remota es otra cosa. Los index no son iguales tal cual los conocemos. Es el servidor el que elige que index va a utilizar en las consultas y para eso nosotros debemos decidir que index crear. No quiero extenderme demasiado sobre este tema ( tampoco soy un entendido ) pero me parece que si decidimos trabajar en forma seria sobre esta tecnología hará falta mucho estudio y ver el manejo de datos de manera diferente . Espero que esto sirva.
saludos

PostPosted: Sun Feb 17, 2008 10:05 am
by Manuel Valdenebro
Horacio,

Podriamos clasificar la mayoria de las aplicaciones que venimos desarrollando los clipperos en dos grupos:

1) Programas domésticos.
2) Programas para pequeñas/medianas empresas (multipuesto o multilugares)

En el segundo grupo es muy conveniente, por cuestiones de seguridad interna (pérdida de datos, reindexados, etc) y externa (encriptación de los datos, copias de seguridad, etc) el usar una base de datos cliente/servidor. Incluso a nivel comercial, no vende igual una aplicación que trabaje con Oracle/MySql que con dbf. Recuerdo que Oracle Express es gratuito.

En este caso, no es obligatorio un conocimiento profundo de la BD y con unos pequeños cambios (sobre todo, si nos preparamos algunas funciones generales de apoyo), podemos poner a trabajar nuestra aplicación con una BD de garantía. En velocidad practicamente igual que con dbf.

Esta claro que si se tienen esos conocimientos y planteamos nuestra aplicación de otra forma (huir de los browse) la cosa mejora, pero lo que quiero decir es que no es OBLIGATORIO.

Otro tema muy importante (en mi opinión) sería trabajar con una BD en un servidor externo (internet). Y quizás con esta opción, si podriamos organizar, entre los foreros que estuvieran interesados, unas prácticas, contratando un servidor compartido y atacando, cada uno desde su ordenador como usuario, la misma BD.

Tambien sería interesante, para no duplicar los comentarios y conseguir mas colaboradores, que el tema lo desarrollaramos exclusivamente en el foro INGLES, aunque se permitieran utilizar españo/inglés.

Amigo...

PostPosted: Sun Feb 17, 2008 5:39 pm
by leandro
Alex amigo:

Es posible que sea el tipo de cursor, lo estoy definiendo de la siguiente manera:

Code: Select all  Expand view
oRsPro:CursorLocation := adUseClient
oRsPro:LockType := adLockOptimistic
oRsPro:CursorType := adOpenDynamic
oRsPro:Source := "SELECT * FROM clientes ORDER BY clie_nom"
oRsPro:ActiveConnection(oCnx)

Es correcto o debo hacerlo de otra forma?

Te hago otra pregunta, como hago para refrescar el recorset en tiempo de ejecucción?

Con ....

PostPosted: Sun Feb 17, 2008 5:43 pm
by leandro
Con la respecto a la documentacion de ado creo que es suficiente para iniciar y poder hacer andar tu aplicación por lo menos a un 80%. El mayor problema para mi ha sido hacer funcionar el recorset en un browse. Es en donde me he topado con mas complicaciones, me gustaria que existiera un manual en donde se explicara el manejo del recorset sobre un browse, cualquiera que este sea.

Ejemplo con ADO + RecordSet + Browse

PostPosted: Mon Feb 18, 2008 9:30 am
by Manuel Valdenebro
Leandro,

No sé si esto es lo que necesitas:


Ejemplo para trabajar con ADO + RecordSet + Browse:
======================================

En una aplicación cliente servidor, debemos tener UNA SOLA
conexión a la Base de Datos (BD). En cambio, tendremos
múltiples RecordSet. Por tanto es conveniente disponer de una
función para facilitar la creación de estos RecordSet de una
forma sencilla. Tambien podemos tener en nuestra librería,
las funciones SKIPPER() y ADOERROR().
En resumen, una vez creado el objeto RecordSet, la actuación
en el Browse es muy parecido a cuando usamos el objeto
Database de FiveWin.

/////////////////////////////////////////////////
Suponemos que ya tenemos en nuestra libreria la función
F_RecordSet y que en la aplicación que estamos programando,
ya existe una Conexión a la BD que llamaremos oCon.
Ahora vamos a crear un objeto RecordSet y mostrarlo
en un Browse.
En nuestro ejemplo, se trata de un programa de recetas
de cocina,
/////////////////////////////////////////////////

FUNCTION BrwCocina(oCon)
Local lSalvar := .f., oDlg, oLbx, oBtn:= ARRAY(9)

// orden SQL
LOCAL cSql := 'SELECT * FROM RECETAS ORDER BY NOMBRE'

// crea recordset
Local oRs := F_RECORDSET ( oCon, cSql, .t. ) // ver al final

// F_recordset devuelve "nil" si hay error
IF oRs == nil
RETURN nil
ENDI

// Caja de Diálogo -----------------------------------------------------
DEFINE DIALOG oDlg RESOURCE "RECETAS" ;
TITLE " Mi libro de recetas con ORACLE"

**
** campos del browse
**
REDEFINE LISTBOX oLbx ;
FIELDS oRs:Fields("CLASE"):value, ;
oRs:Fields("NOMBRE"):value, ;
NUM2STR(oRs:Fields("CONTROL"):value, 10, 0) ;
HEADERS PADC ( "Clase", 18 ) , ;
PADC("Nombre",80), ;
PADC("Ref.",10) ;
FIELDSIZES 90, 290, 20 ;
ID 101 ;
OF oDlg ;
ON DBLCLICK F_ALTA(oRs, .F., oLbx )


oLbx:bLogicLen = { || oRs:RecordCount }
oLbx:bGoTop = { || oRs:MoveFirst() }
oLbx:bGoBottom = { || oRs:MoveLast() }
oLbx:bSkip = { | nSkip | Skipper( oRs, nSkip ) }
oLbx:cAlias = "ARRAY"

** si pulsa <intro>
oLbx:bKeyDown := {|nK| if( nK != VK_RETURN, , F_ALTA(oRs,.F.,aCbx, oLbx) ) }

** para que el browse salga a dos colores
oLbx:nClrPane:={|| IIF(oRs:AbsolutePosition % 2==0,CLR_LGREEN,CLR_LGRAY)}

REDEFINE BUTTONBMP oBtn[1] ID 104 OF oDlg ;
ACTION F_ALTA( oRs, .T., oLbx) ;
MESSAGE "Alta de una nueva receta." ;
PROMPT SPACE(6)+ "&Alta" TEXTRIGHT ;
BITMAP "Alta3"

**
** Baja receta
**
REDEFINE BUTTONBMP oBtn[2] ID 105 OF oDlg ;
ACTION( O_SUPRIMIR ( oRs, "NOMBRE" ), ;
oLbx:Refresh(), ;
oLbx:SetFocus() ) ;
MESSAGE " Eliminar receta activa." ;
PROMPT SPACE(6)+ "&Baja" TEXTRIGHT ;
BITMAP "Cancelar"

// modificar receta
REDEFINE BUTTONBMP oBtn[3] ID 106 OF oDlg ;
ACTION F_ALTA( oRs, .F., oLbx ) ;
MESSAGE " Editar receta activa." ;
PROMPT SPACE(10) + "&Editar" ;
BITMAP "lapiz" TEXTRIGHT

// filtrar
REDEFINE BUTTONBMP oBtn[4] ID 107 OF oDlg ;
ACTION ( FILTRAR ( oRs ), ;
oLbx:Refresh(), ;
oLbx:SetFocus() ) ;
MESSAGE " Filtrar recetas." ;
PROMPT SPACE(10) + "&Filtrar" ;
BITMAP "buscar" TEXTRIGHT

// Imprimir
REDEFINE BUTTONBMP oBtn[5] ID 108 OF oDlg ;
ACTION ( I_LISTA( oRs ), ;
oLbx:REFRESH(), ;
oLbx:SETFOCUS()) ;
MESSAGE " Imprimir la receta activa." ;
PROMPT SPACE( 8 ) + "&Imprimir" ;
BITMAP "imprimir1" TEXTRIGHT

// boton salir
REDEFINE BUTTONBMP oBtn[6] ID 109 OF oDlg ;
ACTION oDlg:End() ;
MESSAGE " Salir del programa." ;
PROMPT SPACE(4)+ "&Salir" TEXTRIGHT ;
BITMAP "salir1"

oDlg:lHelpIcon:=.f.
ACTIVATE DIALOG oDlg CENTERED ;
ON INIT oLbx:SetFocus()

oRs:CLOSE()
oRS:=Nil

RETURN NIL


////////////////////////////////////////
/// funcion que crea un recordset
/// oCon = Objeto conexión a la BD
/// cSql = Orden SQL
/// lVacio = .T./.F. avisar que Ors está vacio
///////////////////////////////////////

FUNCTION F_RECORDSET (oCon, cSql, lVacio)
local oError
local oRs := CreateObject( "ADODB.Recordset" )

oRs:CursorLocation := 3 // adUseClient
oRs:LockType := 3 // adLockOptimistic
oRs:CursorType := 1 // adOpenKeyset
oRs:Source := cSql
oRs:ActiveConnection(oCon)

TRY
oRs:Open( )
CATCH oError
AdoError(oCon, oError)
RETURN nil
END

IF lVacio
IF oRs:EOF .and. oRs:BOF
msgstop ("Fichero vacio")
oRs:CLOSE()
oRs:=Nil
RETURN nil
ENDI
oRs:MoveFirst()
ENDI

RETURN oRs

//////////////////////////////////
/// skipper se usa para saltar en el oRs
/// cuando salta en el browse
////////////////////////////////////////////////////////
FUNCTION SKIPPER( oRs, nSkip )
LOCAL nRec := oRs:AbsolutePosition

oRs:Move( nSkip )

IF oRs:EOF; oRs:MoveLast(); ENDIF

IF oRs:BOF; oRs:MoveFirst(); ENDIF

RETURN oRs:AbsolutePosition - nRec

/////////////////////////////////////////
/// Para informar de un error ADO
////////////////////////////////////////
FUNCTION AdoError(oCon, oError)
LOCAL oTmp

FOR EACH oTmp IN oCon:Errors // oAdoErrors

IF oError == nil
oError := ErrorNew()
oError:Description := "Error desconocido ADO"
ELSE
oError:SubCode := oTmp:NativeError //¡¡¡num. error nativo
oError:Description := oTmp:Description
ENDIF

NEXT

MSGSTOP ( (oError:Description + CRLF ) , ;
" Error " + oError:Operation + ' ' + oError:SubSystem )

RETURN (oError:SubCode) // Código num. del error

///////////////////////////////////////

Para agregar o editar un registro, puedes ver este mensaje:

http://fivetechsoft.com/forums/viewtopi ... ght=#47676

PostPosted: Mon Feb 18, 2008 3:00 pm
by leandro
Gracias Manuel

Muchas gracias por las respuesta voy a probar y cualquier cosa te comento.

Amigo, cuando estoy trabajando con entorno MDI, debo hacer algo especial para que funcione bien el xbrowse?

PostPosted: Mon Feb 18, 2008 5:21 pm
by Biel EA6DD
Bueno este hilo parece que genera bastante interes, me alegro pues cada dia somos mas los que podemos ir aportando conocimientos sobre ADO.

Mauro, a mi no me importaria realizar un manual de ADO, pero como tu bien comentas el tiempo vale dinero, y muchas veces no dispongo de todo el tiempo que quisiera. De momento en el blog voy escribiendo cada cuando puedo, habra epocas con mas articulos, y otras de larga sequia. En cuaquier caso, el tema formacion es algo que me interesa, y puedo llegar a plantearmelo, siempre y cuando me compense la retribución a recibir a cambio.

Al tema, como bien han comentado otros por la red hay bastante información del tema ADO, y en este foro cada vez mas, recuperar un recordset y visualizarlo en un browse con ventanas MDI no tien que llevar ningún problema.
He escrito en mi blog una nueva entrada, con un ejemplo muy básico de ADO para visualizar una tabla en un xBroswe.
http://bielsys.blogspot.com/2008/02/usando-origenes-de-datos-ado-1.html
Espero que os pueda ser de utilidad.

PostPosted: Tue Feb 19, 2008 5:15 pm
by leandro
Biel y Manuel muchas gracias por la ayuda. Funciona de maravilla.

Pero tengo otra preguntica?

Como hago para actualizar el recorset. por ejemplo que quiera cambiar el orden en que se estan mostrando la consulta.

El recorset inicial es:

Code: Select all  Expand view
oVar   := "SELECT * from colores order by CODIGO"
TRY
  oLamcla:oRsColore:=tOleAuto():New("ADODB.RecordSet")
CATCH oError
  MsgStop( "No se ha podido crear el RECORDSET !","Error de Datos" )
END

oLamcla:oRsColore:CursorLocation  := adUseClient //adUseServer
oLamcla:oRsColore:LockType        := adLockOptimistic
oLamcla:oRsColore:CursorType      := adOpenKeyset
oLamcla:oRsColore:Source          := oVar
oLamcla:oRsColore:ActiveConnection( oLamcla:oServer )


Pero quiero actualizar el recorset con la siguiente consulta:

Code: Select all  Expand view
oVar   := "SELECT * from colores order by NOMBRE"


Como lo hago?

De antemano gracias por las respuesta.

PostPosted: Wed Feb 20, 2008 8:30 am
by Biel EA6DD
Si lo único que quieres cambiar es el orden de los registros que ya tienes seleccionados, la mejor opción es utilizar el metodo Sort del recordset.
Code: Select all  Expand view
oRs:Sort:="NOMBRE ASC"

Esta es la manera más rapida y obtima, ya que no implica trafico de red ni carga en el servidor.

En el supuesto que quieras cambiar la sentencia SELECT, el mecanismo seria el siguiente:
Code: Select all  Expand view
      ::oRs:Close()
      ::oRs:Source:="SELECT * from colores order by NOMBRE"
      ::oRs:Open()
      ::oRs:Refresh()