Rafa, lo que te debe estar pasando es que la conexión que usás para los
CursorAdapters es distinta a la que usa el SqlExec, por lo tanto, las
transacciones y las otras instrucciones “no están viendo el mismo canal”,
por así decirlo.

 

La solución de Pancho, como podrás ver, usa la misma conexión ADO para toda
la operatoria entonces no tiene dramas.

 

Otra observación, me parece que si cambiás tu bloque de instrucciones Scan
Alll… EndScan por una sola instrucción Insert into… Select… from… vas a
tener mejor rendimiento (aunque los registros sean poquitos, me parece más
elegante, pero esto es sólo una cuestión de gustos)

 

Salute!

 

De: GUFA@mug.org.ar [mailto:GUFA@mug.org.ar] En nombre de francisco prieto
Enviado el: martes, 24 de mayo de 2011 08:38 a.m.
Para: GUFA List Member
Asunto: [GUFA] OFF TOPIC TRANSACT SQL - manejo de transacciones

 

Rafa,

 

No es que la tenga tan clara sino que me crucé con tantos quilombos en
implementaciones que decidí no utilizar cursoradapters, sino una clase
propia a la que la llame rstocursor... pero eso es harina de otro costal y
si queres en otro momento la vemos.

 

Utilizo, gracias a esta clase ADODB y para trabajar con transacciones
simplemente hago esto:

 

oConexionActual.Execute("SET IMPLICIT_TRANSACTIONS OFF")

 

oConexionActual.Execute("BEGIN TRANSACTION")

 

Luego por ejemplo hago un insert en el  motor de la siguiente forma

 

                                   lcSql="Insert Into ColaEspera
(Orden_cEsp,F_Llegada,Nro_Turno,Estado,Flg_Espera,IdActuante,IdDerivad)
VALUES ("+;

                                               "'"+cOrden.Nro_Turno+"',"+;

                                               "'"+lcLlegada+"',"+;

                                               "'"+cOrden.Nro_Turno+"',"+;

                                               "'ES',"+;

                                               "'P',"+;

                                               "NULL"+","+;

                                               "'"+cOrden.IdDerivador+"')"

                                   Try

 
oConexionActual.Execute(lcSql)

                                   Catch To loError

                                               llHuboError=.T.

                                               lcTexto="La instruccion
"+Chr(13)+Chr(10)+;

 
lcSql+Chr(13)+Chr(10)+;

                                                           "emitio el error
"+Alltrim(Str(loError.ErrorNo))+" - "+loError.Message

 
Strtofile(Transform(Date(),"@E")+" "+Ttoc(Datetime(),2)+"
"+_Screen.UsrName+" ("+;

 
ALLTRIM(_Screen.AppName)+")
"+lcTexto,_Screen.DirApp+_Screen.MisErrores.ArchLog,1)

                                   Endtry

 

 

y finalmente, cuando termino con todo...

 

If llHuboError

            oConexionActual.Execute("ROLLBACK TRANSACTION")

            Messagebox("Se produjo un error interno durante la
grabación.",16,"Avise a Sistemas")

Else

            oConexionActual.Execute("COMMIT TRANSACTION")

Endif

 

Esta operatoria nunca me causo los errores que vos mencionas....

 

Tengo otros quilombos (quien no? :)), pero hasta el momento con SqlServer
fueron todas sonrisas...

 

Saludos,

 

Pancho

Cordoba

El 24 de mayo de 2011 08:24, Rafael Copquin <rcopq...@ciudad.com.ar>
escribió:

Ahora yo tengo una pregunta sobre SQL Server: es el manejo de transacciones,
que es diferente de la forma en que VFP las maneja.

Veamos el ejemplo clásico de una factura. Dos tablas, una cabecera y otra de
detalle.

Yo genero dos cursor adapters vacíos con este código

local cCmd

cCmd = [select * from cabecera where 1=0]
y genero el CA 'curCabecera' && tengo una clase que genera CA , pero es un
código largo que no viene al caso

cCmd = [select * from detalles where 1=0]
y genero el CA 'curDetalles'

Para hacerla corta, al grabar hago algo así

cCmd = [begin transaction]
sqlexec(nHandle,cCmd) && con lo que le mando al SQL la orden de iniciar la
transacción
Luego

   insert into curCabecera ........
  lOK = tableupdate(.t.,.t.,'curCabecera')
  if lOK
     select curFactura && este es un cursor local que opera con una grilla
     scan all
           scatter name oFac
           insert into curDetalles from name oFac
     endscan
     lOK = tableupdate(.t.,.t.,'curDetalles')
  if lOK
    cCmd = 'IF @@TRANCOUNT > 0 COMMIT'
  else
   cCmd = 'IF @@TRANCOUNT > 0 ROLLBACK'
 endif
  sqlexec(nHandle,cCmd)

Pero sé que a esto le falta una pata, porque si provoco un error a propósito
en la grabación, para que la segunda tabla no se grabe, por ejemplo), la
segunda tabla no se graba pero la primera se graba igual.

Intenté usar transacciones manuales antes del begin transaction
#DEFINE DB_TRANSMANUAL  2
SQLSetProp(nHandle, "TRANSACTIONS", DB_TRANSMANUAL)

y luego volverlas automáticas después del end transaction
#DEFINE DB_TRANSAUTO    1
SQLSetProp(nHandle, "TRANSACTIONS", DB_TRANSAUTO)

Pero esto hace que los cursor adapters no graben nada

Me gustaría ver qué mecanismo usan Uds para manejar esto. A lo mejor el
hecho de que estoy usando cursor adapters cambia las cosas respecto de hacer
comandos que graben directamente en las tablas del SQL Server. Después de
todo, un CA es como una vista de VFP, con propiedades y métodos propios,
pero vista al fin.

Pero como Pancho parece que la tiene clara, la pregunta es para vos (o
cualquier otro que también la tenga clara)

Rafael Copquin




 

Responder a