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:
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:
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.