Search  
Friday, May 25, 2012 ..:: Forum ::.. Register  Login
 Forum Minimize
Pentru a putea posta mesaje trebuie să vă înregistraţi.
Notă: Mesajele cu conţinut jignitor sau ilegal (inclusiv cereri de soft piratat) nu sunt acceptate şi vor fi şterse imediat .

Pentru a primi raspunsuri rapide si corecte, scrieti in mesaj ce intentionati sa faceti, ce mesaj de eroare primiti, in ce context si in urma caror actiuni. De asemenea, mentionati versiunea de FoxPro in care lucrati!
Dacă nu specificați versiunea, se consideră VFP 9.0 SP2.

SearchForum Home
  Visual FoxPro  Clase - VCX si PRG  Update in CA...
 Update in CA
 
 8/12/2011 1:51:03 AM
User is offlineEugen Gliga
1052 posts
1st




Update in CA
 (N/A)
Incerc sa inlocuiesc intr-un program mai vechi, o tabela cu un CA. Tabela are structura putin diferita de cea necesara in CA, asa ca trebuie facute niste conversii. Am folosit urmatorul cod, dar probabil ca imi scapa ceva :

            .oCa=Createobject("CursorAdapter")
            .oCa.DataSourceType = "Native"
            .oCa.Alias="CaNomcont"
            .oCa.Tables="Nomcont"
            .oCa.BufferModeOverride=3
            .oCa.KeyFieldList="Simbol"
            .oCa.SendUpdates=.T.
            .oCa.SelectCmd='Select Simbol, Denumire, Icase(Tip="D",1,Tip="C",2,3) As TipC, IIF(Fca="D",.T.,.F.) As Fisa, IIF(Gr2="D",.t.,.f.) As eGmp, Iif(Gr3="D",.t.,.f.) As eCod, Ea As  Eaf  From  Nomcont'
            .oCa.UpdateNameList='Simbol,Nomcont.Simbol, Denumire,Nomcont.Denumire, Tipc,Nomcont.Tip, Fisa,Nomcont.Fca, eGmp,Nomcont.Gr2, eCod,Nomcont.Gr3, Eaf,Nomcont.Ea'
            .oCa.UpdatableFieldList="Simbol,Denumire,Tipc,Fisa,eGmp,eCod,Eaf"
            .oCa.CursorSchema="Simbol c(9),Denumire c(70),Tipc N(1),Fisa L,eGmp L,eCod L,Eaf L"
            .oCa.ConversionFunc="Tipc .n2Tipc, Fisa .l2Char, eGmp .l2Char, eCod .l2Char"
             lOk=.oCa.CursorFill(.T.)

Function n2Tip
Lparameters lnValue
Return Icase(lnValue=1,"D",lnValue=2,"C","B")

Function l2Char
Lparameters llValue
Return Iif(llValue,"D","N")

Problema este ca la Tableupdate nu imi face Update daca fac modificari la  campurile eGmp si eCod, respectiv se actualizeaza doar cursorul iar _Tally=0. Daca nu fac modificari la aceste campuri totul este Ok. Probabil gresesc ceva dar toate exemplele pe care le-am gasit trateaza problemele de conversie si de update destul de sumar.


 8/12/2011 10:32:24 AM
User is offlineDaniel Buduru
2335 posts
1st




Re: Update in CA
 (N/A) Modified By Daniel Buduru  on 8/12/2011 10:36:09 AM)
eCamp, eCod sunt campuri calculate, ele nu exista ca atare in tabela. SQL Update nu actualizeaza astfel de campuri in nici o implementare, fie vfp, fie sql server.
Scoate aceste campuri din UpdateNameList si din UpdatableFieldList.
Va trebui sa scrii propria comanda update in UpdateCmd - si vezi restul proprietatilor cu UpdateCmd in fata. La fel pentru Insert.

O varianta mai simpla este sa pastrezi si campurile sursa in cursor si sa inlocuiesti valorile in aceste campuri in BeforeUpdate si BeforeInsert, sau chiar la editare. Oricum, campurile calculate trebuie scoase din lisa celor actualizabile.


Daniel Buduru
 8/12/2011 11:40:09 AM
User is offlineEugen Gliga
1052 posts
1st




Re: Update in CA
 (N/A)
M-am gandit la faptul asta dar nedumerirea mea consta in faptul ca si campurile Tipc si Fisa sunt campuri calculate dar ele se actualizeaza corect cu conditia sa nu le actualizez simultan cu unul din cele doua care nu merg.
Tabela Nomcont este prost proiectata dar momentan nu o pot modifica deoarece este utilizata de mai multe aplicatii vechi. Solutii sunt dar in aceste conditii inlocuirea tabelelor din programele vechi cu CA in vederea migrarii  la o solutie CS  devine discutabila.



 8/12/2011 4:16:40 PM
User is offlineDaniel Buduru
2335 posts
1st




Re: Update in CA
 (N/A)
Nu m-am uitat cu atentie la tot codul, sunt mereu pe fuga zilele astea.
De ce este inlocuirea discutabila? Solutia e foarte simpla, si este cea pe care o folosesc mereu.Eu insa construiesc clasele ca in designer si le instantiez din biblioteca, nu le populez in cod.
Subclaseaza CA intro clasa proprie, adauga metode BeforeFillRefresh - apelata din BeforeCursorFill si BeforeCursorRefresh, BeforeInsertUpdate - apelata din BeforeInsert si BeforeUpdate, AfterFillRefresh, AfterInsertUpdate, apelate corespunzator, asa incat sa nu trebuieasca sa scrii acelasi cod in doua metode.
Eu personal nu vad nici un avantaj in instantierea unui CA si popularea lui in cod. Nu se poate utiliza niciuna dintre metodele clasei, e doar un alt mod de a scrie un view updatabil.

Daniel Buduru
 8/13/2011 2:14:04 AM
User is offlineEugen Gliga
1052 posts
1st




Re: Update in CA
 (N/A)
Pai de aia e discutabila ca sub forma folosita de mine nici eu nu vad niciun avantaj :)
Nu am mai folosit CA updatabil. Asta a fost doar o incercare si am pierdut ceva timp fara niciun rezultat final. In conditiile in care nu stapanesc foarte bine CA, este discutabila folosirea acestuia pentru inlocuirea tabelelor in conditiile in care prin metode clasice problema se rezolva mai simplu.
Totusi vreau sa merg cu metoda asta pana la capat  ca sa pot evalua mai bine care este solutia cea mai potrivita.
Am creat subclasa CA si am adaugat metodele asa cum ai zis. Daca am inteles bine, clasa nefiind vizuala ea trebuie instantiata tot cu CreateObject, deci codul care trebuie scris in metode  ar trebui scris direct in subclasa. Daca acest cod este diferit de la un caz la altul, asta insemna ca trebuie sa fac cate o subclasa pt fiecare caz.
 8/13/2011 9:03:53 AM
User is offlineDaniel Buduru
2335 posts
1st




Re: Update in CA
 (N/A) Modified By Daniel Buduru  on 8/13/2011 9:19:42 AM)
Un CA poate fi adaugat in designer doar unei clase dataenvironment, iar clasa DE poate fi adaugata unui form in designer prin dataenvironmentclass si dataenvironmentclasslibrary.
Altfel, poate fi instantiat doar in cod, in runtime.
Fie subclasezi clasa pentru fiecare tabela si o instantiezi unde nevoie, fie parametrizezi metoda beforeinsertupdatepdate.
Adaugi o proprietate, BIUcmd sa zicem, in care pui linia de comanda ce trebuie executata. Codul din aceasta metoda:
If not empty(this.BIUcmd) 
 lccmd=this.biucmd
&lccmd
Endif
In runtime, completezi proprietatea biucmd cu "replace all camp1 with ecamp1, camp2 with ecamp2 in this.alias"
Daca ai mai multe linii, se foloseste execscript, tinand cont de faptul ca scriptul este rulat ca un prg.

Daniel Buduru
 8/19/2011 3:47:02 PM
User is offlineEugen Gliga
1052 posts
1st




Re: Update in CA
 (N/A)
Exista vreo limitare de lungime la UpdateCmd din CursorAdapter? Am probleme cu liniile lungi.
Deasemeni am observat ca la comanda Update din UpdateCmd nu-i place clauza "From NumeCursor", mai exact imi da o eroare ciudata.
Fara clauza From merge, dar acum nu mai inteleg cand trebuie s-o folosesc si cand nu.


 8/19/2011 3:47:13 PM
User is offlineEugen Gliga
1052 posts
1st




Re: Update in CA
 (N/A)
Exista vreo limitare de lungime la UpdateCmd din CursorAdapter? Am probleme cu liniile lungi.
Deasemeni am observat ca la comanda Update din UpdateCmd nu-i place clauza "From NumeCursor", mai exact imi da o eroare ciudata.
Fara clauza From merge, dar acum nu mai inteleg cand trebuie s-o folosesc si cand nu.


 8/19/2011 3:53:04 PM
User is offlineEugen Gliga
1052 posts
1st




Re: Update in CA
 (N/A)
Scuze pt postarea dubla. Intradevar am dat de doua ori pe Update pt ca mi s-a parut ca nu merge, dar logic, dupa prima postare mesajul odata transmis ar fi trebuit sa dispara incat sa nu mai poata fi trimis din nou.




 8/19/2011 4:24:34 PM
User is offlineDaniel Buduru
2335 posts
1st




Re: Update in CA
 (N/A)
 Eugen Gliga wrote
Exista vreo limitare de lungime la UpdateCmd din CursorAdapter? Am probleme cu liniile lungi.
Deasemeni am observat ca la comanda Update din UpdateCmd nu-i place clauza "From NumeCursor", mai exact imi da o eroare ciudata.
Fara clauza From merge, dar acum nu mai inteleg cand trebuie s-o folosesc si cand nu.



1. Daca nu ai vfp9.sp2, linia este limitata, nu mai stiu la cate caractere (nu mai stiu daca in sp1 au rezolvat asta sau nu, sp2 e sigur)
Fie faci update la sp2, fie incarci proprietatile care au lungimi mai mari in cod. Limitarea venea de la dimensiune amaxima a unei proprietati caracter, si mi-a dat destul de furca.

2.Update tabela set camp=valoare  este sintaxa utilizabila in cursor adapter

Update tabela set camp=tabela2.camp from tabela2 whete tabela2.id=tabela1id ...  specifica actulizarea unei tabele cu date din alta tabela, ceea ce ca nu accepta.




Daniel Buduru
 8/19/2011 5:15:18 PM
User is offlineEugen Gliga
1052 posts
1st




Re: Update in CA
 (N/A)
Am VFP9 SP2 dar se pare ca nu s-a rezolvat problema. Pentru dimensiuni ale comenzii peste 248 caractere imi apare eroarea "String is too long to fit" Am citit pe undeva ca ar trebui dezinstaltat tot foxul si apoi reinstalat si pus imediat SP2 ca se se rezolve problema.

 8/19/2011 5:59:43 PM
User is offlineDaniel Buduru
2335 posts
1st




Re: Update in CA
 (N/A)
Trebuie recreata biblioteca vcx, ea e configurata pentru proprietati <255 (248)
Am avut problema asta cu bibliotecile create inainte de sp2.
Nu stiu ce sa zic de reinstalarea VFP. E posibil sa mai ramane sechele pe undeva. Mai intai incearca intr-o biblioteca noua si vezi daca merge asa.






Daniel Buduru
 8/25/2011 1:03:13 PM
User is offlineEugen Gliga
1052 posts
1st




Re: Update in CA
 (N/A)
Am rezolvat in mare problemele. Update si Delete functioneaza bine din Ca dar am probleme cu comanda Insert.
Mai exact nu stiu ce sa pun in InserCmd
Varianta care functioneaza este  doar "Insert Into Nomcont (Camp1,Camp2,...) Value ( Var1,Var2,...)"  varianta care presupune ori sa stochez inregistrarea adaugata ori cursorul sa fie pe pozitia respectiva in momentul cand dau Tableupdate
O comanda gen "Insert Into Nomcont Select * From CaNomcont Where Simbol=InsKey" nu functioneaza
In general mi se pare sofisticata utilizarea CA in conditiile in care trebuie sa-ti scrii singur comenzile si trebuie sa gestionezi manual si conflictele de Update.
Am citit si articolul: http://fox.wikis.com/wc.dll?Wiki~CursorAdapterOrNot


 8/25/2011 5:26:22 PM
User is offlineDaniel Buduru
2335 posts
1st




Re: Update in CA
 (N/A)
Tot nu inteleg motivul pentru care trebuie sa-ti scrii singur comenzile.

Creeaza o clasa CA, pune in ea selectul pe care-l doresti.
Pentru campurile pe care le interpretezi in select pune atat campul calculat cat si campul sursa, cel care trebuie actualizat.
Lasa CA pe actualizare automata.
Scoate din lista campurilor actualizabile campurile calculate - cele care nu se regasesc ca atare in tabela sursa..
Inainte de tableupdate(), inlocuieste campurile sursa pentru cele calculate cu valoarea care trebuie stocata in baza de date.
Poti face asta in cod inainte de tableupdate(), sau in CA in BeforeUpdate si BeforeInsert.

Pune o linie de cod oarecare in BeforeUpdate - poate fi si aaaa=0 - pune un breakpoint pe aceasta linie si vezi in parametrii metodei cUpdateInsertCmd, cDelete Cmd care contin comanda Update sql ce se executa, eventual comanda Delete sql, daca tipul de actualizare este delete then insert.

Articolele din fox.wikis m-au facut sa intarzii cu vreo doia ani trecerea la CA.
Acolo e un fel de forum, fiecare cu panseurile proprii. Acolo zicea careva ca nu poti aduce in CA decat campuri dintr-o singura tabela.
Abia cand ,i-a aratat Grig ca are vreo 17 tabele in join in selectul din CA am trecut si eu la CA.
De atunci imi fac propriile teste inainte de a decide ce anume utilizez.

Daca populezi CA in cod, sigur n-ai nevoie de el. Poti lucra foarte bine cu comenzile sql directe.

Daca insa vei trece la un backend pe server sql, comenzi de genul "Insert Into Nomcont Select * From CaNomcont Where Simbol=InsKey" nu functioneaza. CaNomcont este cursor local, iar Nomcont este o tabela pe server. Intre ele este sarma sau aer.
Comanda de actualizare a unei tabele pe server contine explicit valorile care trebuie inserate/actualizate, si nu cursorul din care sa le ia, daca aceste este situat la client.
Serverul este cel care executa comanda, sintaxa ei trebuie sa fie inteleasa de server - atentie la dialectul sql - iar toate tabelele si valorile trebuie sa-i fie accesibile serverului. Cursorul client-side nu este. Punct.

Actualizarea automata din CA functioneaza pe un server. E nevoie InsertCmd, UpdateCmd, DeleteCmd doar daca vrei sa le pui sa faca si altceva decat actualizarea tabelei si a campurilor precizate proprietatile CA.



Daniel Buduru
 8/26/2011 2:08:11 AM
User is offlineEugen Gliga
1052 posts
1st




Re: Update in CA
 (N/A)
Motivul este ca la postul initial mi-ai dat doua solutii: sa-mi scriu singur comenzile sau sa mai adaug niste campuri suplimentare pt campurile calculate. Ghinionul meu a fost ca am ales prima solutie.
Urmeaza s-o testez si pe cealalta.
Am vazut ce comenzi pune CA in cUpdateInsertCmd. In cazul in care se lucreaza in mod row buffering ar fi ok, dar n-am testat ce se intampla in cazul table buffering, respectiv BufferModeOverride=5. Ar trebui sa se genereze cate un update sau insert separat pt fiecare record modificat sau adaugat in cursor. Si imi mai pun o intrebare. S-ar putea ca sintaxa comenzii Update, Delete sau Insert sa difere de la un server la altul. Stie CA sintaxa comenzii sau  genereaza comenzile doar pe sintaxa SQL Server ?


 8/26/2011 2:27:58 AM
User is offlineDaniel Buduru
2335 posts
1st




Re: Update in CA
 (N/A) Modified By Daniel Buduru  on 8/26/2011 2:28:30 AM)
Comenzile Update, Insert, Delete generate de CA au acceasi sintaxa in toate implementarile SQL.
Diferenta intre implementari apare la alte clauze decat update table_name (lista campuri) values (lista valori) where key=valoare cheie.

Se genereaza cate o comanda pentru fiecare inregistrare. Intrucat comada contine valorile campurilor, nu nume de variabile, de forma

Update tabela1 (camp1, camp2) Values (30,'treizeci') where pk='BBB_VVV_DDD'

nu se poate genera o singura comanda pentru un set de inregistrari.
In aceeasi situatie te gasesti daca trebuie sa actualizezi tabele pe server cu sqlexec: vei genera cate o comanda pentru fiecare inregistrare.

BatchUpdateCount specifica numarul de comezi sunt trinise odata catre server:

BatchUpdateCount Property

Specifies the number of update statements sent to the remote data source for buffered tables. When working with this property for regular cursors, use the CURSORSETPROP() and CURSORGETPROP() functions. Read/write.

Adjusting BatchUpdateCount can increase automatic updating performance dramatically.

Daca vei incepe sa lucrezi cu un server sql in backend vei putea decide pe loc ce preferi: sqlexec, remoteview sau cursoradapter.
Ultimele doua solutii genereaza automat comenzile insert / delete / update. In varianta cu sqlexec e necesara o procedura care sa genereze comanda sql imbricand in clar valorile atribuite campurilor.


Daniel Buduru
 8/26/2011 12:40:20 PM
User is offlineEugen Gliga
1052 posts
1st




Re: Update in CA
 (N/A)
Mutumesc de sfaturi. Deocamdata fac teste.


 9/9/2011 8:18:16 PM
User is offlineEugen Gliga
1052 posts
1st




Revin cu o problema legata de acest topic. In principiu toate merg Ok referitor la CRe: Update in CA
 (N/A)
Revin cu o problema legata de acest topic.
In principiu toate merg Ok referitor la CA, dar ma-am lovit de o problema care decurge probabil din modul de utilizare al CA si la care nu-i dau de cap.
Referitor la tratarea conflictelor, m-am folosit de urmatoarele proprietati ale CA:
   WhereType= 3
  ConflictCheckCmd =Chr(13)+Chr(10)+[EXECSCRIPT("IF _tally=0" + CHR(10)+ "ERROR('Update conflict')"  + CHR(10) + "ENDIF")]
  ConflictCheckType=4

La salvarea modificarilor am folosit pe scurt urmatoarea secventa:

lok=Tableupdate(1,.F.,"Canomcont")
If !lok
    =Aerror(laArray)
    If "Update conflict"$laArray[2]
        If Messagebox("Update Conflict. Fortati modificarea ?",36)=6
            lok=Tableupdate(1,.T.,"Canomcont")
            If lok
                Wait Window "Modificarile au fost facute cu succes" Nowa
            Else
                Wait Window "Modificarile nu pot fi facute. Abandonare modificari" Nowa
                Tablerevert(.F.,"CaNomcont")
            Endif
        Else
            Messagebox(" Reverting changes",64)
            Tablerevert(.F.,"CaNomcont")
        Endif
    Else
        If laArray[1]=130 && Blocaj renal
            If Messagebox(laArray[2]+CrLf+"Doriti reincercare ?",36)=6
                Retry
            Else
                Tablerevert(.F.,"CaNomcont")
            Endif
        Else
            Messagebox("Alta eroare a aparut: "+CrLf+Transform(laArray[1])+" - "+laArray[2]+CrLf+"Abandonare modificari",64)
            Tablerevert(.F.,"CaNomcont")
        Endif
    Endif
Endif

Secventa de mai sus functioneaza corect, dar daca apare un confilct si  Tabelupdate() intoarce fals, dupa rezolvarea problemei butoanele din forma nu mai sunt functionale.
Mai exact, se executa codul din buton dar nu se apeleaza alte metode ale formului. De exemplu daca in Click() la butonul de iesire din form am codul Thisform.Click("IESIRE") acesta comanda nu are nici un efect, dar daca scriu explicit Thisform.release atunci pot inchide formul. Daca nu apar conflicte totul functioneaza bine si am mai facut acum un test, blocand tabela din alta instanta si fenomenul nu a mai aparut chiar daca Tableupdate a intors fals. Concluzia mea este ca fenomenul apare doar la Conflict upadate si se datoareaza scriptului din proprietateaConflictCheckCmd.
Exista vreo explicatie pentru acest comportament?


 9/12/2011 11:19:08 AM
User is offlineDaniel Buduru
2335 posts
1st




Re: Revin cu o problema legata de acest topic. In principiu toate merg Ok referitor la CRe: Update in CA
 (N/A)
Ar trebui sa scoti totul din ca.updateconflictcmd
O posibila cauza pentru blocare este coamnda ERROR din execescript, care ridica o exceptie netratata in eventhandlerul aplicatiei.

In cazul unui conflict de actualizare, tableupdate returneaza .f. sau numarul de inregistrari actualizate, daca primul parametru din tableupdate e 2, iar aerror returneaza intr-una din liniile din array eroarea 1585, deci nu este nevoie de o alta tratare.
Poti folosi ca.AfterCursorUpdate pentru a verifica daca actualizarea s-a facut cu succes, si tot ai acces la cErrorArray, in care sunt inregistrarile a caror actualizare a esuat, daca s-a specificat tableupdate(2,...)

_tally nu este un bun indicator  al starii actualizarii. Daca exista un update trigger pe tabela respectiva, trigger care opereaza inserari/actualizari/stergeri in alte tabela, chiar si un count, _tally va returna numarul de linii afectate de ultima comanda, care nu mai este tableupdate.
De asemenea, daca se actualizeaza mai multe inregistrari in aceeasi comanda, _tally nu  va fi 0 in cazul actualizarii esuate. Iar daca este vorba de un server, _tally nu mai are nici o relevanta.

Parerea mea esta ca un conflict de actualizare nu poate fi tratat automat. Nu cred ca se poate decide in cod ce valoare se pastreaza dintre cele doua modificari ale inregistrarii facute de catre doi utilizatori diferiti.
De ex, cineva modifica adresa unui partener, iar altcineva modifica telefonul. Fortarea actualizarii face sa se piarda una din informatii.
Corect este sa prezinti utilizatorului a cauri actualizare a esuat ce contine acum inregistrarea, iar decizia sa o ia utiulizatorul.

Aici este un articol care discuta conflictul de actualizare: http://www.jamesbooth.com/conflicts.htm



Daniel Buduru
 9/13/2011 12:53:36 AM
User is offlineEugen Gliga
1052 posts
1st




Re: Revin cu o problema legata de acest topic. In principiu toate merg Ok referitor la CRe: Update in CA
 (N/A)
Intradevar comanda ERROR era cauza problemelor, insa asta era solutia data de M$ pt VFP8, deoarece Tableupdate intoarcea True chiar daca modificarile nu erau facute in Back-end. In aceasta situatie singura solutie era sa testezi _Tally imediat dupa comanda din UpdateInsertCmd si in cazul _Tally=0 sa simulezi o eroare 1585, astfel incat Tableupdate sa intoarca False. Solutia este data aici:
   http://support.microsoft.com/kb/814184
insa folosirea comenzii ERROR vad are si alte consecinte nefaste. Ulterior am descoperit ca la VFP9 a aparut proprietatea ConflictCheckType, insa eu folosit initial valoarea 4, care adauga automat comanda ConflictCheckCmd  la sfarsitul comenzii  UpdateCmd si am ramas cu aceleasi probleme
Acum am mutat ConflictCheckType pe 3 si  Tableupdate intoarce False in caz de update-conflict cu cod eroare 1585, fara sa mai simulez eu eroarea si astfel am scapat de problema.

Deocamdata sunt  in faza de teste si actualizez doar o singura inregistrare intr-o comanda. Referitor la exemplul cu adresa si telefonul, cazul asta se rezolva de la sine, adica daca setezi proprietatea WhereType=3, nu apare conflict decat daca se modifica acelasi camp, altfel fiecare isi actualizeaza doar campurile modificate de el. Cel mai des intalnit conflict este cand se modifica acelasi camp, adica doua persoane vor sa corecteze o adresa gresita in acelasi timp. Corect este cum ai zis, adica sa-i arati utilizatorului noua valoarea si sa-l lasi sa decida.
  Visual FoxPro  Clase - VCX si PRG  Update in CA...

Search  Forum Home         

 Google Ads Minimize

    

Copyright 2002-2010 Profox   Terms Of Use  Privacy Statement