07. maj 2010 - 12:39Der er
10 kommentarer og 1 løsning
Update transaction som tjekker om data er blevet ændret siden SELECT-udtrækket.
Hej udviklere.
Jeg er ikke den skarpeste MSSQL (jeg benytter i dette tilfælde MSSQL2005) / SQL-person og har oftest kun brugt banale UPDATEs, INSERTS, SELECTs, etc.
Men nu skal jeg vidst bruge noget mere transaktions-orienteret.
Har en database med nogle simple oplysninger (Navn, adresse, telefonnummer, etc.) og disse bliver så trukket ud og fyldt i nogle tekstfelter så den enkelte bruger kan redigere dem.
Hver af applikationerne (winforms) snakker direkte med en database og derfor vil jeg gerne have at når der trykkes "Gem oplysninger", så skal den "låse" det database-record og tjekke om nogle er oplysningerne er ændret (og i såfald hvilke) og hvis de er så skal brugeren have mulighed for "overwrite", "cancel" eller "Get updated data" og hvis de ikke er skal den bare UPDATE.
Er i tvivl om hvordan dette skal gøres og der er garanteret også nemmere måder (og måske indbyggede metoder) som jeg ikke kender til.
Vil det give mening at: BEGIN TRANSACTION SELECT (samme record igen) UPDATE (record med nye oplysninger) Tjek rent kodemæssigt (benytter C#) om der var ændringer fra det første udtræk til det andet. Hvis det var ændringer, så Rollback. Hvis der ikke var ændringer, så Commit.
En let måde at styre det på er at man gemmer created_by og modified_by på tabellerne, og vedligeholder dem via en IU-trigger. Når du selecter din række ud til update husker du det sidst ændret tidspunkt i modified_by. Når du sender din update afsted kan du skrive update tabelnavn where primærnøgle = dinrækkeid AND modified_by=dengamle_modified_by. Hvis den opdaterer nul rækker så er rækken ændret siden sidst. Alternativt kan du også skrive samtlige kolonners gamle værdier i din where-clause når du laver en update. 0 rækker, så er den ændret.
Havde ikke rigtig overvejet den forholdsvis simple/logiske udgave, hvor jeg bare sammenligner med alle de gamle værdier i WHERE-klausulen. Tror jeg benytter mig af denne. Den giver vidst også en fordel i forhold til den først-nævnte løsning, nemlig at hvis folk updater med de samme data som allerede lå der, så vil modified_by jo være ændret, men ingen celler vil réelt være ændret. Så kan den jo poppe følgende op i GUIen:
"Brugeroplysningerne er blevet ændret siden sidst. Følgende er ændret: null", da jeg vil liste de celler som er blevet ændret. På den anden måde er det réelt kun hvis der er ændringer og så kan den vise dem:
"Brugeroplysningerne er blevet ændret siden sidst. Følgende er ændret: Navn er skiftet fra 'Bjarne' til 'Torkild'. Adresse skiftet fra 'Mosebuen 12' til 'Travervænget 11a'.". Jeg kan selvfølgelig kode mig ud af det, men syntes vidst at det giver et bedre kode-flow.
Men vil løsningen så være:
UPDATE Personer WHERE (alle data=alle gamle data) IF rowsaffected=0 then (træk samme person ud igen fra ID) Sammenlign ny-udtrukne data og gamle data. Vis en messagebox med alle uoverensstemmelserne/ændringerne.
Nu bliver jeg helt forvirret over mine egne tanker! :-S
På min sidst-nævnte måde kan en anden bruger jo nå at ændre data fra messageboxen med ændringerne vises til man vælger at overskrive data eller hente ændringerne ind.
Så kan man jo overskrive data på et forkert grundlag... :-/
Du skal vælge løsningen som buzzz foreslår, nemlig med timestamp. Sådan en bruges nemlig til... og det som du skal søge efter hedder 'optimistic concurrency'.
Er umiddelbart desværre forced til at benytte timestamp, da det er op imod MS SQL server 2005...
SELECT en person fra Personer og husk timestamp.
(Bruger bliver præsenteret for data og redigerer i den over tid) (Lykke1) rowsaffected = UPDATE Personer WHERE (ID=id og timestamp=det-huskede-timestamp) IF rowsaffected=0 then (træk samme person ud igen fra ID og husk igen hans timestamp) Sammenlign ny-udtrukne data og gamle data. Vis en messagebox med alle uoverensstemmelserne / ændringerne og afvent enten "overskriv" eller "cancel". Hvis "cancel" så abort. Hvis "overskriv", så gentag lykke1 (\Lykke1)
Ville dette mon give mening (hvis folk altså kan finde hoved og hale i mit abstrakte pseudo-kode! )?
Tanken er så at den bliver ved med at præsentere ændringerne til brugeren indtil der ikke længere er blevet lavet ændringer i mellemtiden og så går den igennem og opdaterer korrekt.
På den måde vil man så ikke kunne tage stilling på forkert baggrund, men vil derimod blive ved med at få at vide at data er blevet ændret indtil dette ikke længere er tilfældet.
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.