Page 1 of 4

ADOBASE, Nueva clase para manipular RECORDSET de ADO

PostPosted: Thu Apr 10, 2008 4:27 pm
by Adolfo
Hi a todos.

Hize esta clase para manejar los recordset de ADO como lo hace la tDataBase de Fivewin

Es mi primera version y cualquier ayuda sera bienvenida, no esta terminada y las cooperaciones son bienvenidas.

La probe con Mysql 5 sin ningun tipo de problema, la pueden descargar de aqui, mis correos estan en su interior para reportar problemas o coas quelequieran agregar.

Se aceptan sugerencias, codigo, trucos, cualquier cosa que podamos usar para mejorarla.


http://200.72.140.34/privado/adobase.rar

Desde Chile
Adolfo

PostPosted: Thu Apr 10, 2008 10:02 pm
by sysctrl2
Adolfo,

personalmente quiero felicitarte por tu contribucion,

los que venimos de dbf a sql la verdad se nos complica

bastante,

ya tenia tiempo esperando algo como la database,

pero para ADO,

vamos a probar,,

saludos.

PostPosted: Thu Apr 10, 2008 10:13 pm
by Patricio Avalos Aguirre
Gracias adolfo por la contribucion

PostPosted: Thu Apr 10, 2008 10:30 pm
by Adolfo
Gracias...

Si alguien puede probarla con Postgress, Oracle, SQL Server u otro RDBMS, por favor que comente los resultados.

Eso

Re: ADOBASE, Nueva clase para manipular RECORDSET de ADO

PostPosted: Fri Apr 11, 2008 8:20 am
by FiveWiDi
Adolfo wrote:Hi a todos.

Hize esta clase para manejar los recordset de ADO como lo hace la tDataBase de Fivewin

Es mi primera version y cualquier ayuda sera bienvenida, no esta terminada y las cooperaciones son bienvenidas.

La probe con Mysql 5 sin ningun tipo de problema, la pueden descargar de aqui, mis correos estan en su interior para reportar problemas o coas quelequieran agregar.

Se aceptan sugerencias, codigo, trucos, cualquier cosa que podamos usar para mejorarla.


http://200.72.140.34/privado/adobase.rar

Desde Chile
Adolfo


Gracias,

Es muy posible que me sea util en un futuro, estoy muy acostumbrado a trabajar con TDbf de Manuel Expósito (muy parecida a la TDatabase).

Entiendo que también puede trabajar con Harbour, cierto?

En el método New() para que sirven oClass, aDatas := {}, aMethods := {} ?

A ver que te parecen estas sencillas modificaciones:
/* ******************** */
METHOD New( oConnect, cTable, cSelect ) CLASS TAdoBase
...

::nFields:=oRs:Fields:Count
::aBuffer := Array( ::nFields )
::Load()

...
return Self
/* ******************** */
METHOD Load() CLASS TAdoBase

local n:=0

//::aBuffer := Array( ::nFields )
for n = 1 to ::nFields
::aBuffer[ n ] := ::AdoGetValue( n - 1 )
next

if ::lOemAnsi
::OemToAnsi()
endif

return nil
/* ******************** */
METHOD SetBuffer( lOnOff ) CLASS TAdoBase

DEFAULT lOnOff := .t.

if lOnOff != nil
::lBuffer = lOnOff
endif

if ::lBuffer
::Load()
else
//::aBuffer := nil
::ClearBuffer()
endif

return ::lBuffer
/* ******************** */
METHOD Find( uExpr ) CLASS TAdoBase

local lFound:=.f.

DEFAULT lSoft := .f.

::oRs:MoveFirst()
::oRs:Find( uExpr )

If !::oRs:Eof()
lFound:=.T.
Endif

if ::lBuffer
if lFound // Inicio Nuevo
::Load()
Else
::ClearBuffer()
EndIf // Fin nuevo
endif

return lFound
/* ******************** */
METHOD Seek( uExpr ) CLASS TAdoBase

local lFound:=.f.

DEFAULT lSoft := .f.

If ::oRs:Supports( adIndex ) .and. ::oRs:Supports( adSeek )
::oRs:Seek( uExpr )

If !::oRs:Eof()
lFound:=.T.
Endif
Endif

if ::lBuffer
if lFound // Inicio Nuevo
::Load()
Else
::ClearBuffer()
EndIf // Fin nuevo
endif

return lFound
/* ******************** */


Saludos
Carlos G.

Re: ADOBASE, Nueva clase para manipular RECORDSET de ADO

PostPosted: Fri Apr 11, 2008 8:30 am
by FiveWiDi
Hola,

más cosas:

/* ******************** */
METHOD End() CLASS TAdoBase

::Close()
Self := nil

return( .t. )
/* ******************** */

Saludos
Carlos G.

PostPosted: Fri Apr 11, 2008 12:15 pm
by Adolfo
Gracias...

Modificamos, revisamos y actualizamos la version.

Mas tests, pruebas...se reciben comentarios.

Desde Chile

PostPosted: Fri Apr 11, 2008 1:34 pm
by Adolfo
Cambios realizados....

Gracias Carlos G.

Nueva Version en

http://200.72.140.34/privado/adobase.rar

Desde Chile
Adolfo

Nombre de columnas en un RecordSet en ADO.

PostPosted: Fri Apr 11, 2008 6:45 pm
by FiveWiDi
Hola Adolfo,

Podrías decirme como puedo obtener los nombres de las columnas de un RecordSet?

Saludos
Carlos G.

Más sugerencias para tu clase.

PostPosted: Fri Apr 11, 2008 6:51 pm
by FiveWiDi
Hola Adolfo,

Siguiendo con tu clase, creo que sería posible añadir otras pequeñas mejoras, a ver que te parecen.

En los siguientes METHOD yo los acabaría con 'Return Self':

_AnsiToOem, _FieldPut, _OemToAnsi, Blank, ClearBuffer, Delete, GOTO, Load, Save.


Esto permitiría hacer cosas así:

oMiTADOBase:Fieldput(5, "calimero" ):Save()
oMiTADOBase:_AnsiToOem():Save()
Msgalert( "Registro Borrado:" + Str( oMiTADOBase:Goto( 3 ):Delete():Recno() , 4, 0 ), "Atención!" )
oMiTADOBase:ClearBuffer():Fieldput(5, "calimero" ):Save()



Modificaría los siguientes METHOD:
/* ***************************** */
METHOD Blank() CLASS TAdoBase

::oRs:MoveLast()
//::Load()
::ClearBuffer()
::lNew:=.T.

return nil
/* ***************************** */
METHOD SetBuffer( lOnOff ) CLASS TAdoBase

Local Old_lBuffer := ::lBuffer

//DEFAULT lOnOff := .t.

if lOnOff != nil

::lBuffer = lOnOff


if ::lBuffer
::Load()
else
::ClearBuffer()
endif

EndIf

return Old_lBuffer
/* ***************************** */


Saludos
Carlos G.

PostPosted: Fri Apr 11, 2008 7:01 pm
by sysctrl2
Holas ADOlfo,

probando con acces me tira un error

te envie a tu correo hotmail el ejemplo,

saludos..

Application
===========
Path and name: C:\SYSCTRL\TESTADO\TESTADO.Exe (32 bits)
Size: 483,840 bytes
Time from start: 0 hours 0 mins 0 secs
Error occurred at: 04/11/08, 13:04:34
Error description: Error ADODB.recordset/6 DISP_E_UNKNOWNNAME: OPEN
Args:

Stack Calls
===========
Called from: win32ole.prg => TOLEAUTO:OPEN(0)
Called from: adobase.prg => TADOBASE:NEW(165)
Called from: testado.prg => TESTADO(17)

PostPosted: Sun Apr 13, 2008 12:40 am
by Adolfo
Holas..

Estoy haciendo las modificaciones sugeridas por Carlos, y agregando mas opciones al metodo Info. para mejor informacion al desarrollar.

Segun la documentacion leida no se pueden usar ciertos tipos de bloqueos con ubicaciones y tipos de cursores. Lo ideal es que se pueda informar antes de seguir.

Carlos .. para los nombres de la columnas usa

oRs:Fields( nField ):Name

Puedes Recuperarlas asi.

For n= 1 to ( oRs:Fields:Count )
AADD( oRsNames, oRs:Fields( n-1 ):Name )
Next

Eso...

SysCtrl2
Reviso el Problema con ACCESS, el error me indica que el Recordset no tiene el metodo open asociado.... :?

Eso es muy raro... con que compilador trabajas, Harbour, xHarbour, version, tienes alguna clase propia de OLE o algo asi...?

Sigo en las pruebas y comento.

PostPosted: Sun Apr 13, 2008 6:29 pm
by FiveWiDi
Adolfo wrote:Carlos .. para los nombres de la columnas usa

oRs:Fields( nField ):Name

Puedes Recuperarlas asi.

For n= 1 to ( oRs:Fields:Count )
AADD( oRsNames, oRs:Fields( n-1 ):Name )
Next


Gracias, no me di cuenta que ya estaba en :New().

Más sugerencias.

Después de capturar los nombres de las columnas en el método NEW(), antes del Return Self, añade:

FieldToData( Self )

y añade este código al final de TADOBase.PRG:
/* ******************************* */
//----------------------------------------------------------------------------//
// Es una adaptación del código de TDBF de Manuel Expósito para TADOBase.
// C.Gelabert 13/04/2008
//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//
// Este función crea un MESSAGE para cada columna.

static function FieldToData( oADODb )

AEval( oADODb:aFldNames, ;
{ | cName, i | GenDataField( oADODb, i ) } ) )

return( oADODb )

//----------------------------------------------------------------------------//
// Se define el MESSAGE de una columna para tomar y dar valores.

static function GenDataField( oADODb, nPos )

Local cNameMethod := oADODb:aFldNames[ nPos ]

//#ifdef __HARBOUR__
local nClassH := oADODb:ClassH

__clsAddMsg( nClassH, cNameMethod, ;
{ | oADODb | oADODb:_FieldGet( nPos ) }, HB_OO_MSG_INLINE )
__clsAddMsg( nClassH, "_" + cNameMethod, ;
{ | oADODb, Val | oADODb:_FieldPut( nPos, Val ) }, HB_OO_MSG_INLINE )
//#else

/* Aquí de momento nada de nada. */

//#endif

return( cNameMethod )

//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//
/* ******************************* */

Estas funciones lo que hacen es crear un MESSAGE para cada columna con el nombre de ésta.
Esto permite que cuando se realiza:
cDomiciliocliente := oADODb:domicilio (por ejemplo)
se esté invocando al MESSAGE DOMICILIO que ahora existirá realmente, y por tanto la gestión de errores no se utilizará.
En consecuencia se optimiza la ejecución del código.

Espero que funcione, yo no lo he probado.
Si es así podrás eliminar "ERROR HANDLER OnError( )" y el METHOD OnError().

Saludos
Carlos G.

PostPosted: Sun Apr 13, 2008 8:41 pm
by andresreyes_mzt
FiveWiDi wrote://----------------------------------------------------------------------------//
// Se define el MESSAGE de una columna para tomar y dar valores.

static function GenDataField( oADODb, nPos )

Local cNameMethod := oADODb:aFldNames[ nPos ]

//#ifdef __HARBOUR__
local nClassH := oADODb:ClassH

__clsAddMsg( nClassH, cNameMethod, ;
{ | oADODb | oADODb:_FieldGet( nPos ) }, HB_OO_MSG_INLINE )
__clsAddMsg( nClassH, "_" + cNameMethod, ;
{ | oADODb, Val | oADODb:_FieldPut( nPos, Val ) }, HB_OO_MSG_INLINE )
//#else

/* Aquí de momento nada de nada. */

//#endif

return( cNameMethod )

//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//
/* ******************************* */

Estas funciones lo que hacen es crear un MESSAGE para cada columna con el nombre de ésta.
Esto permite que cuando se realiza:
cDomiciliocliente := oADODb:domicilio (por ejemplo)
se esté invocando al MESSAGE DOMICILIO que ahora existirá realmente, y por tanto la gestión de errores no se utilizará.
En consecuencia se optimiza la ejecución del código.

Espero que funcione, yo no lo he probado.
Si es así podrás eliminar "ERROR HANDLER OnError( )" y el METHOD OnError().


Difiero un poco de esta optimizacion ...
Efectivamente si debe de ser mas rapida ...
Pero Solo sirve si vas a utilizar un solo Objeto de esa clase ya que si lo que deseas, es usar diversos objetos al mismo tiempo, los campos no deberian ser iguales a los de otro objeto, ya que el acceso seria al campo del ultimo objeto creado y no al que probablemente quieras tener acceso (ya sea cualquier objeto creado anteriormente)...

Esta es una mala practica de la Utilizacion de Clases ...

Saludos,

Andres Reyes

PostPosted: Sun Apr 13, 2008 9:29 pm
by FiveWiDi
andresreyes_mzt wrote:
FiveWiDi wrote://----------------------------------------------------------------------------//
// Se define el MESSAGE de una columna para tomar y dar valores.

static function GenDataField( oADODb, nPos )

Local cNameMethod := oADODb:aFldNames[ nPos ]

//#ifdef __HARBOUR__
local nClassH := oADODb:ClassH

__clsAddMsg( nClassH, cNameMethod, ;
{ | oADODb | oADODb:_FieldGet( nPos ) }, HB_OO_MSG_INLINE )
__clsAddMsg( nClassH, "_" + cNameMethod, ;
{ | oADODb, Val | oADODb:_FieldPut( nPos, Val ) }, HB_OO_MSG_INLINE )
//#else

/* Aquí de momento nada de nada. */

//#endif

return( cNameMethod )

//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//
/* ******************************* */

Estas funciones lo que hacen es crear un MESSAGE para cada columna con el nombre de ésta.
Esto permite que cuando se realiza:
cDomiciliocliente := oADODb:domicilio (por ejemplo)
se esté invocando al MESSAGE DOMICILIO que ahora existirá realmente, y por tanto la gestión de errores no se utilizará.
En consecuencia se optimiza la ejecución del código.

Espero que funcione, yo no lo he probado.
Si es así podrás eliminar "ERROR HANDLER OnError( )" y el METHOD OnError().


Difiero un poco de esta optimizacion ...
Efectivamente si debe de ser mas rapida ...
Pero Solo sirve si vas a utilizar un solo Objeto de esa clase ya que si lo que deseas, es usar diversos objetos al mismo tiempo, los campos no deberian ser iguales a los de otro objeto, ya que el acceso seria al campo del ultimo objeto creado y no al que probablemente quieras tener acceso (ya sea cualquier objeto creado anteriormente)...

Esta es una mala practica de la Utilizacion de Clases ...

Saludos,

Andres Reyes


Cuanta razón tienes.

Me dejé una cosa importantísima que hace TDBF, y es crear una 'nueva' clase para cada DBF diferente que va a utilizar. Supongo que teniendo en cuenta ese 'pequeño' detalle deja de ser una mala práctica.

Adolfo, por lo tanto, lo que he sugerido no vale sin esa asignación previa.

En fin, si puedo seguiré mirando como hacerlo.

Saludos y gracias por estar al quite; hubiese destrozado la clase.
Carlos G.