Stanąłem przed takim problemem, muszę przenieść aplikację z modelu dwuwarstwowego, klient->sql_serwer_bazy_danych , do modelu trójwarstwowego , klient->serwer_aplikacji->sql_serwer_bazy_danych .
użwywam Delphi 2010 Enterprise, więc postanowiłem użyć technologii Datasnap, i pierwsze próbne zadanie jakie sobie postawiłem to utworzenie po stronie klienta dwupolowej tabeli, z polami "ilosc" i "cena" , następnie przesłanie tej tabeli do serwera aplikacji, który ma zwrócić całkowitą wartość tableli i zsumować dla całej tabeli iloczyn pól "ilosc"
"cena" , czyli umownie (sum(ilosc*cena)).
W tym celu po stronie klienta tworzę tabelę klasy TClientDataset , z polami "ilosc" i "cena" , wypełniam ją konkretnymi wartościami i przesyłam do serwera przy pomocy metody "proxy.pobierz_sprzedaz(ClientDataSet1)"
Serwer prawidłowo oblicza i zwraca całkowitą wartość tabeli.
Problem pojawia się , kiedy chcę usunąc z pamięci stworzoną tabelę "ClientDataSet1" (metodą "free") , bo wtedy pojawia się wyjątek "invalid pointer operation"
To wyglada tak, jakby wywołanie metody "proxy.pobierz_sprzedaz(ClientDataSet1)" w jakis sposób modyfikowało samą tabelę "clientdataset1" w taki sposób , ze nie można w prosty sposób, czyli metodą "free", zwolnic obiektu,
sprawdzenie czy jest "clientdataset1.active" również genereuje taki sam wyjątek.
Opisany objawy w żadnym stopniu nie zależą o tego co się dzieje po stronie serwera, bo w skrajnym testowym przypadku serwer zupełnie nic nie robił z otrzymanym datasetem , zupełnie go pomijał i od razu zwracał stałą wartośc równą "0"
poniżej kod programu
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, WideStrings, DbxDatasnap, DB, SqlExpr, DBClient, StdCtrls;
type
TForm1 = class(TForm)
DATASNAPCONNECTION: TSQLConnection;
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses Unit1;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
proxy: TServerMethods1Client;
ClientDataSet1: TClientDataSet;
begin
ClientDataSet1 := TClientDataSet.Create(self);
ClientDataSet1.FieldDefs.Add('ilosc', ftfloat);
ClientDataSet1.FieldDefs.Add('cena', ftfloat);
ClientDataSet1.CreateDataSet;
ClientDataSet1.Append;
ClientDataSet1.FieldByName('ilosc').AsFloat := 10;
ClientDataSet1.FieldByName('cena').AsFloat := 20;
ClientDataSet1.Post;
ClientDataSet1.Append;
ClientDataSet1.FieldByName('ilosc').AsFloat := 120;
ClientDataSet1.FieldByName('cena').AsFloat := 220;
ClientDataSet1.Post;
try
if not self.DATASNAPCONNECTION.Connected then
self.DATASNAPCONNECTION.Open;
proxy := TServerMethods1Client.Create
(self.DATASNAPCONNECTION.DBXConnection);
//// Wykomentowanie poniższej linii , powoduje że nie pojawia się wyjątek
self.Memo1.Lines.Add(formatfloat('#,##0.00',
proxy.pobierz_sprzedaz(ClientDataSet1)));
finally
proxy.Free;
self.DATASNAPCONNECTION.close;
/// poniższa linia generuje opisany powyżej wyjątek
ClientDataSet1.Free;
end;
end;
end.