[Delphi]informatie van (client)dataset in database inserten

Pagina: 1
Acties:
  • 101 views sinds 30-01-2008
  • Reageer

  • SilentStorm
  • Registratie: November 2000
  • Laatst online: 18-03 14:45
Ik ben bezig een programma te herschrijven dat een synchronisatie moet uitvoeren met een database. Het origineel heeft deze synchronisatie verwerkt in een alternatief van het administratieprogramma, dat deze data gebruikt. Deze versie verschilt intussen enorm van de reguliere versie en 'kan' hierdoor ook niet meer worden bijgehouden.

Om nu echter met een uniforme versie van dit programma te komen, ben ik aan het proberen om een los programma te schrijven, teneinde deze synchronisatie te kunnen doen. Ik weet dat het schrijven van een dergelijke applicatie normaal een uitgebreid verhaal is met aanpassingen voor automatisch gegenereerde id's, concurrency, uitwisselingsproblemen van allerlei soorten, etc.

Zoals het nu staat volstaat het echter om de synchronisatie zo te gebruiken als eerder ook gedaan werd: we laten het delphi afhandelen door een 2tier client/server app te gebruiken. Ik heb de server geschreven die basically gewoon de benodigde tabellen aanbied via een dataprovider. Met de client kan ik die via een dcomconnectie weer uitlezen en synchroniseren.

Het onderdeel dat overblijft, en waar ik eigenlijk niet iets zinnigs over heb kunnen vinden (ik ben bang meer door het niet kunnen bedenken van een logische zoekterm dan de hoeveelheid data), is het versturen van de data die ik nu in clientdatasets heb, naar een database (we gebruiken interbase, voor zover relevant :) ). Misschien kan ik de benodigde gegevens een voor een uitlezen en vervolgens via een insert in sql per record invoeren. Dat laatste lijkt me echter ten eerste nogal omslachtig; nou zal het aantal records per tabel niet boven de 10k uitkomen, maar dit kan gewoon niet snel gaan. Ik hoop eigenlijk op een methode waarmee ik de data meteen kan laten doorstromen naar tabellen en dan die opslaan of iets dergelijks.

Dus om het simpel te formuleren: er moet data worden uitgewisseld tussen 2 tabellen. Als iemand een tut/howto/article of gewoon wat info heeft over hoe zoiets geschiet met twee lokale databases kom ik er hiervoor waarschijnlijk ook wel uit.

Alvast bedankt voor de aandacht :)

On a sidenote: is het ook mogelijk om een query te koppelen aan een clientdataset? Als ik dat via een datasource doe en geen database opgeeft bij de query, krijg ik de mededeling dat de database niet gevonden kan worden op de plaats waar de xml van de clientdatasource wordt neergezet. Er wordt volgens die beschrijving echter gezocht naar een paradox database met een db, dbf of een txt extensie. :/ :?

Localhost is where the heart is


Verwijderd

Een client dataset kan normaal gesproken zelf de data posten in de database waaruit de data komt zonder dat er code voor nodig is. Helaas werk ik zelf al weer enige tijd nauwelijks met Delphi dus de call die je moet aanroepen is mij ontschoten. De client dataset post dan bij aanroep echter de veranderde data naar de database waaruit de data oorspronkelijk komt. Helaas zitten hier wat mitsen en maaren aan (met name als je een query gebruikt die meerdere tabellen in 1 clientdataset propt) maar die kun je allemaal oplossen in de events van de client dataset. Met name de Before Post, After delete events e.d. zijn wel handig :)

In de delphi handleiding staat hierover echter het nodige op papier wat dit precies uitlegt.

  • SilentStorm
  • Registratie: November 2000
  • Laatst online: 18-03 14:45
De code die ik daarvoor nodig heb had ik al in de vorige versie van het programma. Ik meen zo uit mijn hoofd dat slechts 2 keywords zijn. Een voor update, namelijk 'refresh' (van clientdataset naar database) en een voor synchroniseren 'applyupdates' (database > clientdataset). Ik hoopte echter, dat ik de clientdataset als een soort buffer, in plaats van een reguliere database kon gebruiken.

Dus in plaats van op de server een query neer te zetten als provider, wilde ik alleen alle nieuwe data uit de tabellen uitwisselen met die van de clientdataset (die daarvoor eerst gevuld zou moeten worden met data uit de andere database).

Ik ben momenteel wat aan het expirimenteren door voor die tweede database ook een tabel neer te zetten, een dataprovider en een clientdataset, die vervolgens verwijst naar de eerder genoemde. Het idee voor de totale verbinding wordt dus vervolgens
[server] Database > 36 tabellen > 36 dataproviders [/server]
[client]DComconnection > 36 clientdatasets <-> 36 clientdatasets < 36 dataproviders < 36 tabellen <- Database[/client]. Eens zien of ik er zo uitkom. Het is wel aankloten met invullen :P dus ik expirimenteer zo eerst wat met 1. Ik post nog :)

Localhost is where the heart is


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 18:16

Creepy

Tactical Espionage Splatterer

SilentStorm schreef op 07 november 2004 @ 18:47:
De code die ik daarvoor nodig heb had ik al in de vorige versie van het programma. Ik meen zo uit mijn hoofd dat slechts 2 keywords zijn. Een voor update, namelijk 'refresh' (van clientdataset naar database) en een voor synchroniseren 'applyupdates' (database > clientdataset). Ik hoopte echter, dat ik de clientdataset als een soort buffer, in plaats van een reguliere database kon gebruiken.
Een clientdatasat houdt standaard alleen wijzigingen bij t.o.v. de originele query, en de originele query/data. Als je een clientdataset dus gaat syncen met de originele data worden alleen de wijzigigen doorgestuurd. Save na een paar wijzigingen in de CDS de CDS maar eens als XML weg en bekijk dan de XML handmatig. Dan zul je de wijzigigen zien staan.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • SilentStorm
  • Registratie: November 2000
  • Laatst online: 18-03 14:45
Je hebt gelijk met het automatisch wijzigen. Mijn punt met die vorige quote was ook meer gericht op het feit dat het ook te forceren is. Zoals ik nu bezig ben (dus alleen sync'en en de data verder niet gebruiken) is hard sync'en nodig. De keywords waar ik aan refereerde waren trouwens refresh (waarna je de data met 'savetofile' opslaat en 'applyupdates' uitvoert) en post.

Ik heb de opzet intussen een heel stuk veranderd. Ik heb voor beide databases een server object / applicatie gemaakt en sync deze nu via een client app. Dus eerst synchroniseer ik de lokale data met die van de lokale database (die ik aanroep via dcom in een andere applicatie). Als dat gebeurd is kan ik hetzelfde doen met de andere database en zijn beide databases gelijk. (theorie :) )

Waar ik tegenaan loop met deze 'oplossing' is dat er data gelockt is bij het uitvoeren van een post (vernieuwde data van de cds naar de database sturen). Hoe en wat er gelockt is is nog wat onduidelijk. Ik krijg bij elke tabel waar ik post op aanroep een 'EvariantArrayLockedError' met 'Variant or safe array is locked'. Ik heb het overigens geprobeert via zowel dezelfde datamodule waarbij alleen de dcomserver veranderd wordt als een datamodule met feitelijk dezefde inhoud; voor het geval de lock in een van de componenten zat.

Deze bovenstaande krijg ik bij het afvangen van fouten in het synchronisatiestukje. In delphi zelf krijg ik nog (hiervoor zelfs) een foutmelding op dezelfde code, nl een exception van 'EDBClient': 'operation not applicable'. Op beide foutmeldingen geeft google me niet veel. Ik kan me ook voorstellen dat ik wat onconventioneel bezig ben. Het idee van de eerste post staat eigenlijk nog; als iemand een meer directer manier weet voor synchroniseren houd ik me aanbevolen. Ik expirimenteer ondertussen (vandaag niet meer) door met de applicatie en kijk wat ik er zelf van kan maken.

Alvast bedankt voor de gedane moeite :)

Localhost is where the heart is


Verwijderd

De truc die ik ooit toe heb gepast is zowel een dataprovider als een clientdataset te gebruiken. Bij de provider kun je via het OnGetData event de complete dataset vullen met willekeurige data zolang die maar aan het model voldoet wat in de ClientDataset gedefinieerd is.
Ook kun je via het onupdaterecord event per record in de dataset bepalen hoe je die wilt afhandelen. Zowel de oude data als de nieuwe data is in principe beschikbaar zodat je complete custom queries kan bouwen. (Of het desnoods naar een textfile kan schrijven of.....) De help file geeft mij het volgende voorbeeld

code:
1
2
3
4
5
6
7
8
9
10
procedure TDBClientTest.ProviderUpdateData(Sender: TObject; DataSet: TCustomClientDataSet);
begin
  with DataSet do
    whilenot EOF do
    begin
      if UpdateStatus = usDeleted then
        LogDelete(DataSet, UserName, Date, Time);
      Next;
    end;
end;


in plaats van loggen kun je hier dus van alles doen.

  • SilentStorm
  • Registratie: November 2000
  • Laatst online: 18-03 14:45
Ik zag het voorbeeld staan inderdaad en ik ben over de laatste paar dagen steeds meer gaan zien van de mogelijkheden van de clientdataset. Een van de belangrijkste dingen heb ik echter ongeveer vanaf het begin over het hoofd gezien :/ Aangezien de vorige applicatie zo gegevens kon uitwisselen met de 'hoofd' database, zonder verder iets op te geven over welke data er nieuw is, etc, kreeg ik het idee dat er op een of andere magische wijze een verschil werd aangemerkt of iets dergelijks. Uiteraard is dit niet het geval. Ik vond vandaag uiteindelijk toch nog een nuttig document over multitier applicaties met database (de help kan ik wel mee uit de voeten, maar de site van borland... :o )
As data packets are transferred to the ClientDataset, they are placed in the Data property. The ClientDataset will use this property to allow other components to view and edit the data it contains. As users edit the data, the changes will be stored in the Delta property. By using this method, the ClientDataset only has to pass the changed records back to the server. This is more efficient than passing the entire dataset across the wire every time.
Ik denk dat dat wel ongeveer alles zegt over de haalbaarheid van mijn plan om delphi de synchronisatie af te laten handelen buiten het programma om. Ik ga mijn schema omzetten; dat wordt toch een speciale clientapp :/ Met wat ik nu heb is dat een eitje ( :P ), maar ik vind het wat jammer dat het originele idee ermee verloren gaat. Ik ga er echter geen dagen, zoniet weken instoppen om bij tientallen tabellen timestamps toe te voegen, zooi te gaan populaten, dubbele autoincrement id's afvangen en alles wat er bij komt. Daarbij weet ik nog steeds niet hoe je lokaal twee databases aan elkaar vast knoopt ;)

Iig, bedankt voor de duwtjes in de goede richting. Ze brachten me geen van alle precies in de richting die ik zocht, maar boden me wel net dat perspectief vanwaaruit ik weer verder kon zoeken. Jullie tijd wordt geappricieerd, Jan Klaasen, creepy, bedankt! Ik ga nu voor de 'makkelijke versie', met de clientdatasets in de applicatie.ekend helaas wel weer een hoop werk met cds'jes, tabellen, query's en dataproviders invullen

Localhost is where the heart is

Pagina: 1