A żaby było jeszcze śmieszniej to w komponentach typu IBX najlepiej działa odpowiednik TTable. Ma sprytny generator SQL, który potrafi robić prawie wszystko automatycznie. Nie tylko edycję danych, ale też sortowanie i filtrowanie... Jeśli dobrze pamiętam, a mogę nie pamiętać - używałem tego na poważnie ponad 15 lat temu ;-)
Tylko za używanie TTable w komunikacji serwer-klient zakazywałbym pisania programów ;) No i nie jestem pewny, ale tu filtry wykonują się po stronie klienta? Jeśli tak to w ogóle porażka.
To znaczy, że nie masz pojęcia jak to jest zrealizowane pod spodem (a twierdzisz, że "Jednak warto wiedzieć co się dzieje pod spodem." ) i powtarzasz stereotypy rodem z BDE.
A to nieprawda! O tym tez już tu pisałem i zostałem prawie zbanowany przez indolentów...
Sam poczytaj, zalecam dokładnie i ze zrozumieniem, czym naprawdę jest TFDTable w odniesieniu d relacyjnych baz danych na przykładzie FireDAC:
http://docwiki.embarcadero.com/RADStudio/XE8/en/Browsing_Tables_(FireDAC)
I nie, nie tylko w FireDAC są takie mechanizmy w oparciu o komponent typu Table.
O filtrowaniu/sortowaniu po stronie klienta już pisałem. I nie, nie jest to porażka. To zależy po prostu. Ale na pewno porażką będzie twierdzenie, że zawsze porażką jest sortowanie po stronie klienta lub serwera. To zależy...
I co z tego? Ten komponent robi to automatycznie i jest trywialny w użyciu.
A przecież o to pytającemu chodziło, prawda?
Poza tym pisałem też o akcjach - zauważyłeś?
Tak zauważyłem. Jednak warto wiedzieć co się dzieje pod spodem. Mimo, że i tak dużą część roboty odwala IDE to warto wiedzieć jak z palca usunąć/zupdate'ować dany rekord.
Tu nie ma o czym dyskutować, pełna zgoda.
Dla mnie to 20 lat temu pisało się tak jak pokazałeś; wpisanie SQL, użycie generatora do UpdateSQL, trzymanie tego w DFM a i pewnie komponentów typu TQuery/TIBDataSet w DataModule. To jest dla mnie coś, czego nie mogę ścierpieć.
Wiesz, generujesz tylko raz ewentualnie jak zmieniasz strukturę tabeli. Tylko nie wiem w czym Ci przeszkadza trzymanie komponentów w DataModule? Chcesz tworzyć wszystko runtime (), czy trzymać na formatkach? Akurat pytam na poważnie, bo sam mam czasem problem gdzie trzymać komponenty bazodanowe.
Nie trzymam niczego na formatkach, bo i nie mam formatek w IDE...
Wszystko jest generowane automatycznie w runtime. Layout formatek też, który później można sobie dostosować za pomocą drag'n'drop w aplikacji, a nie w IDE.
Nie trzymam żadnego komponentu typu query na formatce czy DataModule.
Wszystko trzymam w metadanych, system je konsumuje i tworzy co trzeba.
Po co mam trzymać ileś set czy tysięcy zapytań na DataModule? To ani nie jest wygodne rozwiązanie w pracy na co dzień...
Zwłaszcza, że mam tylko jedną instancję danego zapytania na DataModule i nie mogę łatwo pozyskać kolejnej. Mogę oczywiście skopiować komponent, poprawić co trzeba i już. A potem biedzić się przy drobnej zmianie struktury tabel w bazie...
A to bez sensu...
Wolę rozwiązanie na kształt fabryki. Potrzebuję jakichś danych, proszę o nie fabrykę. Ona się martwi skąd ma to pobrać i jak ma to przygotować. Ja oczekuję od niej gotowego i poprawnie skonfigurowanego Query.
I co z tego?
Wiem, że tak pisze 90% ludzi w Delphi. A niech sobie piszą na zdrowie.
A, że ja robię to zupełnie inaczej (i nie, nie używam intensywnie narzędzia typu ORM) to moja sprawa i mam swoje powody.
Natomiast nie chodzi o oto, że moja racja jest fajniejsza. Nie mam zamiaru nikogo do niczego przekonywać.
Tak, jednak ja mam doświadczenie z różnymi stylami pisania takich aplikacji bazodanowych i w zasadzie nie widzę rozwiązania które by było idealne. Każde ma swoje wady, a niektóre mnie wręcz odrzucają jak trzymanie komponentów bazodanowych na formatkach.
Ja robię to zupełnie inaczej, ale to nie jest rozwiązanie które da się opisać w dwóch zdaniach.
To może kod pokażę:
Aby utworzyć dwa zapytania master-detail piszę coś takiego:
Kopiuj
FboTppDeviceTool := TboTppDeviceTool.Create();
FboTppDeviceTool.SQLParser.OrderBy.Clear;
FboTppDeviceTool.SQLParser.Where.Clear.Add(FboTppDeviceTool.PKFields);
FboTppDeviceTool.SQLParser.CommitSQL();
FboTppToolOutput := TboTppToolOutput.Create(nil);
FboTppToolOutput.RelationToMaster(FboTppDeviceTool);
Mam dwie instancje TFDQuery, połączone ze sobą. Nie ma ani grama kodu na DataModule. Nie łączę ręcznie datasetów.
Nie tworzę na etapie zapytania powiązań przez WHERE.
Robi się samo, ale trzeba było napisać sporo kodu pod spodem.
Za to jest wygodniej, szybciej i elastyczniej.
Dzięki w/w mechanizmom definiuję zapytania tylko na poziomie zbioru danych; określam SELECT bez warunków i sortowania. To co potrzebne w kontekście filtrów i sortowania załatwia automat lub można to wydziergać ręcznie, ale obiektowo (taki Builder dla WHERE).
Np. taki kod:
Kopiuj
function TdDSController.IsUniqueFieldValue(AField: TField): Boolean;
var
lDS, lFindDS: TDADQuery;
lEntity : TDEntity;
begin
Result := True;
lDS := AField.DataSet as TDAdQuery;
lEntity := lDS.dFLEXConf.Entity;
if Assigned(lEntity) then
begin
lFindDS := UpdateConnection.CreateQuery(lEntity.IDEntity, True);
try
lFindDS.SQLParser.OrderBy.Clear;
lFindDS.SQLParser.Where.Clear.Add(AField.FieldName);
lFindDS.SQLParser.CommitSQL([AField.Value], [AField.DataType]);
lFindDS.SetFastForward(False, False, 1);
lFindDS.OpenEx(AField.Value);
Result := lFindDS.IsEmpty;
finally
lFindDS.Free;
end;
end;
end;
Potrafi sprawdzić czy wartość danego pola jest unikalna dla dowolnego zapytania.
Podkreślam - ten kod zadziała poprawnie dla każdego zapytania SELECT. Nie muszę tego rozpatrywać za każdym razem.