Overview

OData

Integrazione OData nel framework per route metadata-driven, con fallback controllato su provider alternativi. Supporto completo read + CRUD + $expand + $count=true wrapper.

Scope

  • Uso di endpoint OData come sorgente dati di wuic-data-source.
  • Allineamento con metadata tabella/colonna per rendering UI e comportamento runtime.
  • Relazione con flusso di scaffolding iniziale e bootstrap progetto.
  • Navigation properties auto-generate da colonne lookupByID per abilitare $expand nativo.

Esempi

Riferimenti Metadata

  • Il routing e la configurazione base restano guidati dai metadati (md_route_name, colonne, filtri, sort, paging).
  • In md_props_bag puoi forzare il provider tramite endpoint (esempio: {"endpoint":{"type":"odata","uri":"/odata/Orders"}}).
  • Anche le colonne lookup possono puntare a un endpoint OData custom via mc_props_bag.lookup.endpoint (vedi Widget Lookup).
  • Il datasource continua a usare filterInfo, sortInfo, pageInfo; lato provider OData avviene la traduzione in query OData.
  • Per i dettagli metadata trasversali vedi Metadata.

Navigation properties auto-generate (lookupByID → $expand)

Il generatore EF dinamico (MetadataModelGenerator) emette automaticamente una navigation property su ogni colonna con mc_ui_column_type = 'lookupByID' e mc_ui_lookup_entity_name che punta a una route esposta in WebAPI. Convenzione di naming: strip del suffisso Id / ID dal nome FK → nome nav property (es. stateProvinceIDStateProvince). Con EnableLowerCamelCase() attivo l'EDM espone la nav in camelCase (stateProvince).

Effetti pratici:

  • il $metadata contiene <NavigationProperty Name="stateProvince" Type="...Stateprovinces" /> sull'entity Cities;
  • GET /odata/Cities?$expand=stateProvince restituisce ogni riga con l'oggetto correlato inline ({... "stateProvince": { "stateProvinceID": 1, "stateProvinceName": "Alabama" }});
  • il controller EntitiesController.Get traduce $expand=navProp in .Include(navProp) EF Core (LEFT JOIN SQL).

Limiti attuali: solo $expand top-level (niente nested $expand=a($expand=b)); sub-options OData dopo la nav name (es. $expand=stateProvince($select=...)) vengono ignorate — .Include include l'intera entita' correlata.

Response shape e $count=true wrapper

  • Default (senza $count): endpoint ritorna un plain JSON array ([{...}, {...}]) per compatibilita' con i consumer legacy del framework (DataProviderOdataService.select, DataProviderWebserviceService, ecc.) che leggono response as any[].
  • Opt-in OData v4 ($count=true nella query): endpoint ritorna il wrapper standard { "value": [...], "@odata.count": N } dove N e' il totale calcolato dopo $filter/$orderby ma prima di $skip/$top. Usare quando serve il totale paginato (es. pager UI).

CRUD completo via EntitiesController

L'endpoint OData generico espone l'intera suite RESTful su /odata/{EntitySet}:

  • GET /odata/{EntitySet} — list con $top/$skip/$filter/$orderby/$select/$expand/$count=true.
  • POST /odata/{EntitySet} — insert, body JSON con le colonne (le colonne null nel payload vengono skippate cosi' SQL applica il DEFAULT lato DB, supportando PK IDENTITY/SEQUENCE/GUID automaticamente e colonne con default temporali/audit).
  • PATCH /odata/{EntitySet}({key}) — update parziale, body JSON con subset colonne; la PK in path.
  • DELETE /odata/{EntitySet}({key}) — delete per chiave singola.

Gating lato metadata (riga _metadati__tabelle):

  • mdexposeinwebapi = 1 (obbligatorio per qualsiasi CUD, altrimenti 403).
  • mdserviceenableinsert, mdserviceenableedit, mdserviceenabledelete = 1 per le rispettive operazioni.
  • Vedi anche tab metadata "Servizio web" nel metadata-editor.

Metadati Tab "Servizio web" (OData/API)

Nel metadata editor tabella, il tab Servizio web governa l'esposizione API e i gate operativi lato servizio.

  • md_expose_in_webapi: espone la route nei servizi Web API/OData.
  • md_service_apply_default_filter: applica anche lato servizio il md_default_filter.
  • md_service_enable_delete: abilita delete da endpoint servizio.
  • md_service_enable_edit: abilita update/edit da endpoint servizio.
  • md_service_enable_insert: abilita insert da endpoint servizio.
  • md_service_enable_detail: abilita endpoint dettaglio record.
  • md_service_enable_clone: abilita clone record lato servizio.
  • md_service_enable_logging: abilita logging operazioni lato servizio.
  • md_service_page_size: page size lato servizio (Pagesize nel tab UI).

Snippet inline consigliato:

  • md_expose_in_webapi=true, md_service_enable_insert=true, md_service_enable_edit=true, md_service_enable_delete=true, md_service_page_size=100.

Nota pratica:

  • md_pagesize regola il paging UI standard; md_service_page_size regola il paging lato endpoint servizio.
  • Per OData conviene tenere allineati i flag servizio con le reali capability del backend (read-only vs read/write).

Riferimenti Scaffolding

  • Il bootstrap (firstRun) prepara contesto applicativo e connessioni iniziali; dopo scaffolding puoi agganciare route a endpoint OData.
  • Nel setup iniziale conviene validare subito route, metadati tabella/colonne e mappature minime per evitare mismatch OData/metadata.
  • Riferimento operativo: Scaffolding iniziale.

Flusso Operativo Consigliato

1. Definisci/valida route metadata e colonne minime.

2. Configura provider endpoint OData in md_props_bag.endpoint.

3. Verifica lettura lista con filtro/sort/paging dalla UI.

4. Se usi auth OData, allinea le chiavi appsettings (enableODATAAuthentication e policy correlate).

Note pratiche

  • OData e metadata non sono alternativi: il metadata resta la sorgente di comportamento UI, OData la sorgente dati.
  • In caso di differenze schema, aggiorna prima metadati colonna (mc_*) e poi rifinisci endpoint/query OData.