Overview

OData

OData integration in the framework for metadata-driven routes, with controlled fallback to alternative providers. Full read + CRUD + $expand + $count=true wrapper support.

Scope

  • Using OData endpoints as a data source for wuic-data-source.
  • Alignment with table/column metadata for UI rendering and runtime behavior.
  • Relationship with the initial scaffolding flow and project bootstrap.
  • Navigation properties auto-generated from lookupByID columns to enable native $expand.

Examples

Metadata References

  • Routing and base configuration remain driven by metadata (md_route_name, columns, filters, sort, paging).
  • In md_props_bag you can force the provider via endpoint (example: {"endpoint":{"type":"odata","uri":"/odata/Orders"}}).
  • Lookup columns can also point to a custom OData endpoint via mc_props_bag.lookup.endpoint (see Widget Lookup).
  • The datasource continues to use filterInfo, sortInfo, pageInfo; on the OData provider side, translation into an OData query occurs.
  • For cross-cutting metadata details see Metadata.

Auto-generated Navigation Properties (lookupByID → $expand)

The dynamic EF generator (MetadataModelGenerator) automatically emits a navigation property on every column with mc_ui_column_type = 'lookupByID' and mc_ui_lookup_entity_name pointing to a route exposed in WebAPI. Naming convention: strip the Id / ID suffix from the FK name → nav property name (e.g., stateProvinceIDStateProvince). With EnableLowerCamelCase() active, the EDM exposes the nav in camelCase (stateProvince).

Practical effects:

  • the $metadata contains <NavigationProperty Name="stateProvince" Type="...Stateprovinces" /> on the Cities entity;
  • GET /odata/Cities?$expand=stateProvince returns each row with the related object inline ({... "stateProvince": { "stateProvinceID": 1, "stateProvinceName": "Alabama" }});
  • the EntitiesController.Get controller translates $expand=navProp into .Include(navProp) EF Core (SQL LEFT JOIN).

Current limits: only top-level $expand (no nested $expand=a($expand=b)); OData sub-options after the nav name (e.g., $expand=stateProvince($select=...)) are ignored — .Include loads the entire related entity.

Response Shape and $count=true Wrapper

  • Default (without $count): the endpoint returns a plain JSON array ([{...}, {...}]) for compatibility with legacy framework consumers (DataProviderOdataService.select, DataProviderWebserviceService, etc.) that read response as any[].
  • Opt-in OData v4 ($count=true in the query): the endpoint returns the standard wrapper { "value": [...], "@odata.count": N } where N is the total computed after $filter/$orderby but before $skip/$top. Use when you need the paginated total (e.g., UI pager).

Full CRUD via EntitiesController

The generic OData endpoint exposes the entire RESTful suite on /odata/{EntitySet}:

  • GET /odata/{EntitySet} — list with $top/$skip/$filter/$orderby/$select/$expand/$count=true.
  • POST /odata/{EntitySet} — insert, JSON body with columns (null columns in the payload are skipped so SQL applies the DEFAULT DB-side, automatically supporting IDENTITY/SEQUENCE/GUID PKs and columns with temporal/audit defaults).
  • PATCH /odata/{EntitySet}({key}) — partial update, JSON body with subset of columns; PK in path.
  • DELETE /odata/{EntitySet}({key}) — delete by single key.

Gating on the metadata side (_metadati__tabelle row):

  • mdexposeinwebapi = 1 (required for any CUD, otherwise 403).
  • mdserviceenableinsert, mdserviceenableedit, mdserviceenabledelete = 1 for the respective operations.
  • See also the "Web service" metadata tab in the metadata-editor.

"Web Service" Tab Metadata (OData/API)

In the table metadata editor, the Web Service tab governs API exposure and operational gates on the service side.

  • md_expose_in_webapi: exposes the route in Web API/OData services.
  • md_service_apply_default_filter: also applies md_default_filter on the service side.
  • md_service_enable_delete: enables delete from the service endpoint.
  • md_service_enable_edit: enables update/edit from the service endpoint.
  • md_service_enable_insert: enables insert from the service endpoint.
  • md_service_enable_detail: enables record detail endpoint.
  • md_service_enable_clone: enables record clone on the service side.
  • md_service_enable_logging: enables operation logging on the service side.
  • md_service_page_size: service-side page size (Pagesize in the UI tab).

Recommended inline snippet:

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

Practical note:

  • md_pagesize controls the standard UI paging; md_service_page_size controls service endpoint paging.
  • For OData, it is advisable to keep service flags aligned with the backend's actual capabilities (read-only vs read/write).

Scaffolding References

  • The bootstrap (firstRun) prepares the application context and initial connections; after scaffolding, you can attach routes to OData endpoints.
  • During initial setup, it is advisable to immediately validate routes, table/column metadata, and minimum mappings to avoid OData/metadata mismatches.
  • Operational reference: Initial Scaffolding.

Recommended Operational Flow

1. Define/validate route metadata and minimum columns.

2. Configure the OData endpoint provider in md_props_bag.endpoint.

3. Verify list reading with filter/sort/paging from the UI.

4. If using OData auth, align appsettings keys (enableODATAAuthentication and related policies).

Practical Notes

  • OData and metadata are not alternatives: metadata remains the source of UI behavior, OData the data source.
  • In case of schema differences, first update column metadata (mc_*) and then refine the OData endpoint/query.