Hola, te respondo las preguntas:

1) los links estaban en español originalmente y fueron luego traducidos al inglés y al portugués. Pero desde hace varios años, el dueño de la revista solamente dejó disponibles las versiones en inglés

2) podés hacer cursor adapters de varias tablas en la sentencia select sql. Pero lo mejor es actualizar una sola tabla, aunque la consulta sea de varias tablas. Los campos de la tabla que vas a actualizar los definís en las propiedades updatefieldlist, updatenamelist y keyfieldlist (en todas ellas tenés que incluir la clave primaria de la tabla, porque si no, no te va a funcionar) También tenés que poner la propiedad sendupdates en true.

3) En cuanto a TierAdapter, preguntales a los autores Rubén Rovira y Martín Salías

Saludos

Rafael Copquin



El 25/07/2012 07:50 p.m., pablo.oviedo escribió:
Gracias, empece con cursoradapter y me trabe. Se pueden usar un
cursoadapter que incluya columnas de distintas tablas? me tira error
cuando quiero refrescar algunos campos del cursor luego de una inserción.

También estoy viendo TierAdapter. Los link que me pasaron, es posible que
esta información este en español?

Existe alguna documentación sobre TierAdapter que describa todas las
clases, metodos y propiedades del frameworks a parte del diagrama de UML
que esta en el sitio de Martin?

saludos


-----Original Message-----
From: Rafael Copquin <[email protected]>
To: "GUFA List Member"  <[email protected]>
Date: Tue, 24 Jul 2012 16:32:07 -0300
Subject: [GUFA] CursorAdapter

Te paso un ejemplo bien completo de cómo lo hago yo:

** creacion de las tablas en sqlserver
** en la vida real tienen más campos, pero estos son los mínimos que
deberían tener

CREATE TABLE [dbo].[DETALLE](
      [FECHA] [date] NOT NULL,
      [TIPODOC] [char](3) NOT NULL,
      [DOCNUM] [char](8) NOT NULL,
      [CODIGO] [char](30) NOT NULL,
      [CANTIDAD] [int] NOT NULL,
      [PRECIO] [numeric](10, 4) NOT NULL,
      [DT] [datetime] NOT NULL,
      [IDETALLE] [int] IDENTITY(1,1) NOT NULL,
      [IDCABECERA] [int] NOT NULL,
   CONSTRAINT [PK_DETALLE] PRIMARY KEY CLUSTERED
(
      [IDDETALLE] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY
=
OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY],
   CONSTRAINT [CN_IDDETALLE] UNIQUE NONCLUSTERED
(
      [IDDETALLE] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY
=
OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [dbo].[CABECERA](
      [FECHA] [date] NOT NULL,
      [CUENTA] [char](4) NOT NULL,
      [TIPODOC] [char](3) NOT NULL,
      [DOCNUM] [char](8) NOT NULL,
      [IVA] [numeric](10, 2) NOT NULL,
      [TOTAL] [numeric](10, 2) NOT NULL,
      [IDCABECERA] [int] IDENTITY(1,1) NOT NULL,
      [DT] [datetime] NOT NULL,
   CONSTRAINT [PK_IDCABECERA] PRIMARY KEY CLUSTERED
(
      [IDCABECERA] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY
=
OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]


** lo siguiente se hace en Visual FoxPro

** generación de un cursor adapter para la tabla CABECERA

Local cCmd,cSch,cUFL,cUNL,lOK

Text to cCmd noshow pretext 15
SELECT
      FECHA ,
      CUENTA ,
      TIPODOC ,
      DOCNUM ,
      IVA ,
      TOTAL ,
      IDCABECERA ,
      DT
   FROM CABECERA WHERE 1=0
EndText

Text to cSch noshow pretext 15
      FECHA D,
      CUENTA C(4),
      TIPODOC C(3),
      DOCNUM C(8),
      IVA N(10,2),
      TOTAL N(10,2),
      IDCABECERA I,
      DT T
EndText


Text to cUFL noshow pretext 15
      FECHA ,
      CUENTA ,
      TIPODOC ,
      DOCNUM ,
      IVA ,
      TOTAL ,
      IDCABECERA ,
      DT
EndText

Text to cUNL noshow pretext 15
      FECHA        CABECERA.FECHA,
      CUENTA       CABECERA.CUENTA,
      TIPODOC      CABECERA.TIPODOC,
      DOCNUM       CABECERA.DOCNUM,
      IVA          CABECERA.IVA,
      TOTAL        CABECERA.TOTAL,
      IDCABECERA   CABECERA.IDCABECERA,
      DT           CABECERA.DT
EndText

cUFL        = Chrtran( cUFL, Chr(13) + Chr(10), " " )
cUNL       = Chrtran( cUNL, Chr(13) + Chr(10), " " )
cSch        = Chrtran( cSch, Chr(13) + Chr(10), " " )
cCmd      = Chrtran( cCmd, Chr(13) + Chr(10), " " )

Use in Select("")

lOK = .t.

If !PemStatus(thisform,'oCA',5)
     thisform.AddProperty('oCA')
EndIf

Try

      Thisform.oCA = Createobject("CursorAdapter")

      lOK = .t.

Catch to oErrores

      MessageBox("No se pudo generar el objeto CursorAdapter"+;
      Chr(13)+oErrores.message,16,"Atención",2000)

      lOK = .f.

Finally
EndTry


If lOK = .t.
     try
         With thisform.oCA
              .DataSourceType     = "ODBC"
              .DataSource         = thisform.nHandle
              .alias                 = "curCabecera"
              .tables             = "cabecera"
              .BufferModeOverride = 5
              .keyfieldlist        = "idcabecera"
              .sendupdates         = .T.
              .usetransactions    = .f.   && si están en falso, no usa
transacciones y funciona entonces ponerlas en manual en SQL Server
              .selectcmd             = cCmd
              .updatablefieldlist = cUFL
              .updatenamelist     = cUNL
              .cursorschema       = cSch
              .cursorfill()
         EndWith

         Select curCabecera

     Catch to oErrores

          MessageBox("No se pudo generar el Cursor
"+Chr(13)+oErrores.message;
          ,16,"Atención",2000)

          lOK = .f.

     endtry
endif

Return lOK

**(hacer otro cursor adapter para la tabla DETALLE y obtener el cursor
curDetalle)

** la sentencia where 1=0 genera un cursor vacío. Esto es para que
llenes el cursor adapter con los datos necesarios antes de
** grabar. Estos datos salen de textboxes, grillas, cálculos, etc.

** rutina de grabación

Local lOK,nPK,cCmd,nResults,lBatchMode

SQLExec(thisform.nHandle,'BEGIN TRANSACTION')
SQLSetProp(thisform.nHandle, "TRANSACTIONS", 2 )   && pone las
transacciones en manuales

Select curCabecera
Scatter name oCab blank fields except idcabecera
With oCab
      .fecha    = Date()
      .cuenta   = '1234'
      .tipodoc  = 'FRA'
      .docnum   = '12345678'
      .iva      = 210.00
      .total    = 1210.00
      .dt       = Datetime()
EndWith

** grabación de la cabecera y obtención de la clave primaria generada
** el campo idcabecera es autoincremental

Insert into curCabecera from name oCab

lOK = TableUpdate(.t.,.t.,'curCabecera')

If lOK = .t.

      nPK      = 0
      nResults = 0
      cCmd     = [select @@IDENTITY as pk ]

      lBatchMode = SQLGetProp(thisform.nHandle,"BatchMode" )

      SQLSetProp(thisform.nHandle,"BatchMode" ,.f.)

      SQLExec(thisform.nHandle,cCmd,'curPK')

      Do while nResults <> 2
         nResults = SQLMoreResults(thisform.nHandle)
      enddo

      SQLSetProp(thisform.nHandle,"BatchMode" ,lBatchMode)

      nPK = curPK.pk
      Use in Select('curPK')

      Select curFactura      && cursor auxiliar usado en el form para
insertar las lineas de detalle de la factura
                                          && tiene la misma estructura
que la tabla detalle del sql server

      Scan all
           Scatter name oDet fields except iddetalle
           With oDet
                .fecha      = Date()
                .tipodoc    = 'FRA'
                .docnum     = '12345678'
                .idcabecera = nPK       && aqui pasa a ser la clave
foránea
                .dt         = Datetime()
           *** los campos codigo, cantidad y precio ya están en el
objeto, obtenidos con SCATTER NAME
           endwith
           Insert into curDetalle from name oDet
      EndScan
      lOK = TableUpdate(.t.,.t.,'curDetalle')

endif

If lOK = .t.

     SQLCommit(thisform.nHandle)

Else

     SQLRollback(thisform.nHandle)

endif

SQLSetProp(thisform.nHandle,'Transactions',1 )     && transacciones
automáticas

A los cursor adapters les ponés la propiedad usetransactions en falso,
para que no maneje las transacciones directamente. Acordate que en SQL
Server, las transacciones son automáticas a menos que las pongas en
manual. Esto hace que cada vez que insertás,borrás o modificás un
registro, se abra y cierre una transacción automáticamente. No te
sirve
para el caso de una factura, porque si te da error alguna de las
tablas,
no podés cancelar una transacción completa. En cambio, si las
transacciones las ponés en manual, solamente se completa la
transacción
cuando le mandás un SQLCommit (o SQLRollback si falla)
Tenés que poner las transacciones del SQLServer en manual antes de
comenzar a grabar y luego de cerrar la transacción las ponés
nuevamente
en automáticas,para que el SQL Server siga funcionando normalmente

Fijate en estos artículos

http://www.universalthread.com/ViewPageArticle.aspx?ID=667

http://www.universalthread.com/ViewPageArticle.aspx?ID=817

Rafael Copquin




Responder a