Často programátoři v Delphi používají pro přístup k jednotlivým položkám datasetu vyhledávání přes FieldByName. Takový kód je celkem čitelný, ale lehce může sklouznout k velkým časovým ztrátám.
Při používání FieldByName je dobré si uvědomit, že tato metoda vrací následníka TField, což je klasický objekt. Podle mne původní myšlenka autorů Delphi byla, že jednotlivé položky (fields) budou primárně definovány v IDE (přesně tak jak se to dá dodnes dělat). Můžeme to chápat jako ekvivalent instancí kontrolů (např. TButton), které také definujeme v IDE (ale můžeme je vytvářet dynamicky a hledat přes jméno - ale dělá se to jen výjimečně).
Ale časem se ukázala definice controls v design modu jako velmi výhodná, kdežto definice polí datasetu už ne všem vyhovující a místo toho programátoři generují dotazy a k polím přistupují dynamicky právě přes FieldByName.
Problémem je, že až do některé z nových verzí nebyla implementace této metody nijak optimalizovaná. Pravděpodobně v Delphi 2010 (nebo 2009) byla implementace předělána na implementaci za pomocí hash tabulky, ale přesto se dá ještě ušetřit.
Pokud nemáte tak vysokou verzi Delphi a nelíbí se Vám níže popsané řešení, můžete použít skvělé řešení které publikoval Zarko Gajic - hooknutí TDataset za pomocí háčku, který jsem zde již popisoval (nahrazení metody za běhu - viz. dole tag hacky) na rychlejší vyhledávání - Faster FieldByName.
Ale zpět. Klasickým takovým případem může být procházení otevřeného datasetu přes všechny položky, něco jako (je to příklad, ano znám SQL):
while not ds.Eof do
begin
dmPrice := dmPrice + ds.FieldByName('Price').AsCurrency;
ds.Next;
end;
případně cokoliv, co mnohokrát přistupuje k jedné položce.
Pokud uvedený příklad napíšeme následujícím způsobem, dostaneme pravděpodobně nejrychlejší klientské řešení (i mnohem rychlejší než pomocí hash table - jen ne tak komfortní), a to díky použití nalezeného objektu. Pak totiž už jen přistupujeme pouze k jeho proměnným a metodám:
var
oPriceField: TField;
…
oPriceField:= ds.FieldByName('Price');
while not ds.Eof do
begin
dmPrice := dmPrice + oPriceField.AsCurrency;
ds.Next;
end;
end;
A poslední, snad zajímavý, kód:
with ds.FieldByName('Price') do
begin
if AsCurrency > 0 then
Price := Price + AsCurrency
else
Debit := Debit - AsCurrency;
end;
což pro mne představuje krásné využití with pro ušetření jednoho volání FieldByName (pro každou větev). Opět se jedná pouze o ideový příklad.
Jen bych upozornil, že cílem článku mělo být jen upozornění na možné problémy. Je věcí každého jak bude svůj program psát. V každém případě pokud máte problém s rychlostí, zkuste pro zjištění úzkého hrdla použít profiler (i když se to dnes už moc nenosí - slušně řečeno).