Autor Téma: Field mapping  (Přečteno 445 krát)

Offline J_M

  • Nováček
  • *
  • Příspěvků: 21
  • Karma: 0
Field mapping
« kdy: 01-10-2017, 14:01:24 »
Prosím o radu. Pro svoji rozsáhlejší aplikaci jsem se rozhodl použít FireDac, doposud vše správně fungovalo, až s použitím SQL dotazu kde jsou počítaná pole nastal problém.

Jednoduchý příklad, jak se chyba projeví:
Databáze SQLite.
Mám TFDQuery s naplněným SQL dotazem který obsahuje počítaná pole, fieldy jsou persistentní, vygenerované v IDE.
V době generování dotčené tabulky obsahovaly data a fieldy se vytvořily správně - tedy správného typu, v mém případě TFloatField.
Problém nastane když do sql dotazu přidám where kterým odfiltruji všechny záznamy - tedy prázdný recordset.
Po znovuotevření query, Firedac očekává všechny fieldy typu TWideString a skončí chybou. "Expecting: Float actual: WideString". Co s tím?

Mapping použít nemůžu, protože ten nelze aplikovat na jednotlivé fieldy.

Předem dík, za rady.

Edit: abych byl konkrétní, přikládám ještě SQL. Bez toho Where je vše ok, s ním ko.

SELECT MA.NAME,
IFNULL(SUM(DI.DOCITEM_VALUE), 0.0) AS DOCITEM_VALUE,
IFNULL(SUM(DI.DOCITEM_VALUE_BASE), 0.0) AS DOCITEM_VALUE_BASE,
IFNULL(SUM(DI.ID_DOCITEM_VALUE_UNIT), 0) AS ID_DOCITEM_VALUE_UNIT,
IFNULL(AVG(DI.PRICE), 0.0) AS AVG_PRICE 
FROM MATERIAL MA LEFT JOIN DOCITEM DI ON DI.ID_MATERIAL = MA.ID

WHERE MA.NAME = 'abcd'

GROUP BY MA.ID


« Poslední změna: 01-10-2017, 14:29:25 od J_M »

Offline J_M

  • Nováček
  • *
  • Příspěvků: 21
  • Karma: 0
Re:Field mapping
« Odpověď #1 kdy: 01-10-2017, 15:20:43 »
Problém snad vyřešen. Použil jsem mapping. Přes MapRule.NameMask lze nastavit konkrétní field.
Tak zatím nic :)

Online Delfin

  • Hrdina
  • ****
  • Příspěvků: 440
  • Karma: 23
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
Re:Field mapping
« Odpověď #2 kdy: 01-10-2017, 16:40:14 »
Pouzij typecast. Sloupce s vyrazy s sebou nenesou metainformace a FireDAC "hada" datovy typ z prvniho zaznamu. No a pokud resultset nevrati ani jeden zaznam, FireDAC pouzije wide string. Priklad reseni (Ty samozrejme pouzij patricne pseudo datove typy):

Kód: MySQL [Vybrat]
  1.    MAX(MyFloatField) AS "MyFloatField::FLOAT"
  2.    MyTable

Mapova pravidla by fungovat mohla ale je to jen naplast, definice typu je reseni (mohlo by se totiz taky stat, ze z prvniho zaznamu FireDAC neuhodne presny datovy typ). Jeste dodam, ze tohle je specialita FireDAC pouze pro SQLite.

Btw. nejsi to Ty?
« Poslední změna: 01-10-2017, 16:47:01 od Delfin »
A co chudinky ovce? Koupíš jim snad plovací vesty? Nebo jim nasadíš chůdy? Ještě lepší, kdybys je zkřížil s delfíny na ovce hopkavé!

Offline J_M

  • Nováček
  • *
  • Příspěvků: 21
  • Karma: 0
Re:Field mapping
« Odpověď #3 kdy: 01-10-2017, 17:27:52 »
Ne, to jsem nebyl já, ale také jsem na to narazil:)

Typecast se mi moc nelíbí - složitý zápis selectu a taky bych musel upravit parser sql ve kterém s tím nepočítám.
Mapování fieldů je pro mě ideální. Mám totiž v paměti celou strukturu databáze včetně typů, kterou načítám z DB při spuštění aplikace.
To se pak využívá pro automatické vytvoření fieldů každého query ještě než se otevře.
Přidat mapování byla záležitost pár minut. Tedy až potom co jsem na to přišel :)

Online Delfin

  • Hrdina
  • ****
  • Příspěvků: 440
  • Karma: 23
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
Re:Field mapping
« Odpověď #4 kdy: 01-10-2017, 18:18:30 »
Typecast se mi moc nelíbí - složitý zápis selectu a taky bych musel upravit parser sql ve kterém s tím nepočítám.

Libi, nelibi, typecast (resp. hint datoveho typu) je reseni. Pravidla mapovani jsou naplast. Navic jak uz jsem psal, FireDACu se nemusi vzdy podarit uhodnout z prvniho zaznamu datovy typ. Zvaz napr. vyraz nad dvema INTEGER sloupci se SUM(). FireDAC si z prvniho zaznamu precte hodnotu treba 1, a zacne sloupec povazovat za INTEGER. A co se stane kdyz budou ve sloupcich nasledujicich zaznamu maximalni hodnoty INTEGER (tj. secte se MAXINT + MAXINT)?

Parseru staci zavolat metodu FDSQLiteTypeName2ADDataType (ze jmena sloupce dokaze z dane notace parsovanim rozbit vse potrebne pro popis sloupce).
« Poslední změna: 01-10-2017, 18:24:30 od Delfin »
A co chudinky ovce? Koupíš jim snad plovací vesty? Nebo jim nasadíš chůdy? Ještě lepší, kdybys je zkřížil s delfíny na ovce hopkavé!

Offline J_M

  • Nováček
  • *
  • Příspěvků: 21
  • Karma: 0
Re:Field mapping
« Odpověď #5 kdy: 01-10-2017, 18:27:43 »
Ale to je přece v pořádku že neuhodne jaký typ tam patří, od toho to mapování je ne?
Pokud je pro dané pole SourceDataTyp = dtUnknown, přiřadím jako TargetDataType := dtSpravnyTyp a jede to.
Takhle mě to stálo pár minut a nemusím dál nic řešit.
A co třeba změna typu atributu v databázi - s typecastem bych pak musel opravovat všechny SQL dotazy.

Online Delfin

  • Hrdina
  • ****
  • Příspěvků: 440
  • Karma: 23
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
Re:Field mapping
« Odpověď #6 kdy: 01-10-2017, 18:48:23 »
Ale to je přece v pořádku že neuhodne jaký typ tam patří, od toho to mapování je ne?

Mapovani je pro migraci prip. optimalizaci preciznosti desetinnych cisel, ne pro urcovani neznamych datovych typu. Pro sjednoceni v SQL prikazech se daji pouzit spolecna makra (konkretne substitucni promenne) a vyvtorit si system datovych domen. Napr.:

Kód: Delphi [Vybrat]
  1. FDQuery.SQL.Text := 'SELECT MAX(MyField) AS "MyFieldAlias!MyFieldType" FROM MyTable'; { "domena" MyFieldType }
  2. FDQuery.MacroByName('MyFieldType').AsRaw := '::INTEGER'; { plneni hodnot maker je pak spolecne pro vsechny prikazy }
  3. FDQuery.Open;

Ale bud jak bud. Korekni postup je pouzit typecast (datovy hint). Pokud si podle nazvu sloupcu nekdo zacne mapovat nezname datove typy nechavam na svobodne volbe kazdeho :)
« Poslední změna: 01-10-2017, 18:56:51 od Delfin »
A co chudinky ovce? Koupíš jim snad plovací vesty? Nebo jim nasadíš chůdy? Ještě lepší, kdybys je zkřížil s delfíny na ovce hopkavé!

Offline J_M

  • Nováček
  • *
  • Příspěvků: 21
  • Karma: 0
Re:Field mapping
« Odpověď #7 kdy: 01-10-2017, 22:45:28 »
Souhlasím, že tvoje řešení je pro SQLite správné. Ale já se snažím mít tu aplikaci pokud možno univerzální, nezávislou na konkrétní DB.

Citace
Pokud si podle nazvu sloupcu nekdo zacne mapovat nezname datove typy nechavam na svobodne volbe kazdeho

Já to přece nemapuji jen podle názvu sloupců, ale podle metadat načtených z databáze, což je ve výsledku stejné, jako bych si do SQL dotazu ručně dopisoval typy, akorát si to psaní ušetřím. ;)

Online Delfin

  • Hrdina
  • ****
  • Příspěvků: 440
  • Karma: 23
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
Re:Field mapping
« Odpověď #8 kdy: 01-10-2017, 23:37:58 »
Souhlasím, že tvoje řešení je pro SQLite správné. Ale já se snažím mít tu aplikaci pokud možno univerzální, nezávislou na konkrétní DB.

Pravda, tohle je jen pro SQLite. Rekl bych ale, ze kdyby bylo treba, tahle vlastnost by existovala i pro dalsi podporovane DBMS. Tim chci rict, ze ostatni DBMS timto problemem nejspis netrpi a vrati odpovidajici popis datoveho typu i pro sloupce vracejici hodnoty vyrazu. Napr. PostgreSQL (vic DBMS ted nemam po ruce a nechce se mi startovat VM ::)) ma podobny typecast primo vestaveny (a dokaze popsat sloupec i bez nej).

Já to přece nemapuji jen podle názvu sloupců, ale podle metadat načtených z databáze, což je ve výsledku stejné, jako bych si do SQL dotazu ručně dopisoval typy, akorát si to psaní ušetřím. ;)

Co se tyce nazvu, pak jsem asi nepochopil poznamku "Přes MapRule.NameMask lze nastavit konkrétní field.". Pokud pouzivas datove typy sloupcu kterych se vyraz tyka, pak bych jen upozornil na funkce AVG (napr. pro INTEGER datove typy muze byt FLOAT) a TOTAL (napr. muze pretect INTEGER pro INTEGER sloupec). SUM by mel skoncit pri preteceni vyjimkou.
« Poslední změna: 01-10-2017, 23:48:02 od Delfin »
A co chudinky ovce? Koupíš jim snad plovací vesty? Nebo jim nasadíš chůdy? Ještě lepší, kdybys je zkřížil s delfíny na ovce hopkavé!

Offline J_M

  • Nováček
  • *
  • Příspěvků: 21
  • Karma: 0
Re:Field mapping
« Odpověď #9 kdy: 01-10-2017, 23:55:51 »
Citace
Co se tyce nazvu, pak jsem asi nepochopil poznamku "Přes MapRule.NameMask lze nastavit konkrétní field.
Ano, to mapování mají řešené tak, že se musí použít název sloupce v aplikaci. Já ten název však získávám z sql parseru vždy před použitím query, takže nemůže dojít k žádné chybě.

Citace
pak bych jen upozornil na funkce AVG (napr. pro INTEGER datove typy muze byt FLOAT)

To je pravda, pro tyhle případy používám standardní SQL Cast a parser mi zase vrátí správný typ. Takže další specifikace typu není nutná a je to univerzálnější.

Online Delfin

  • Hrdina
  • ****
  • Příspěvků: 440
  • Karma: 23
  • SW konzultant
    • Verze Delphi: 2009, Tokyo
Re:Field mapping
« Odpověď #10 kdy: 02-10-2017, 00:21:36 »
Ano, to mapování mají řešené tak, že se musí použít název sloupce v aplikaci.

Nemusi. Mapovani se da definovat hromadne pro vsechny sloupce. Da se ale upresnit pro konkretni sloupce maskou jejich jmen.
A co chudinky ovce? Koupíš jim snad plovací vesty? Nebo jim nasadíš chůdy? Ještě lepší, kdybys je zkřížil s delfíny na ovce hopkavé!

 

S rychlou odpovědí můžete používat BB kódy a emotikony jako v běžném okně pro odpověď, ale daleko rychleji.

Jméno: E-mail:
Ověření:
Datový typ v Delphi, který má True a False: