Granit.DataExchange provides a complete import/export pipeline for tabular data.
Imports follow a guided flow: upload a file, preview headers, receive intelligent
column mapping suggestions, confirm, then execute with batched persistence and
detailed error reporting. Exports use a whitelist-based field definition, optional
presets, and automatic background dispatch for large datasets. Both pipelines
integrate with Wolverine for durable outbox-backed execution when installed.
flowchart LR
A[Upload file] --> B[Extract headers]
B --> C[Preview rows]
C --> D["Suggest mappings<br/>4-tier"]
D --> E["User confirms<br/>mappings"]
E --> F[Parse rows]
F --> G[Map to entities]
G --> H[Validate rows]
H --> I[Resolve identity]
I --> J["Execute batch<br/>INSERT / UPDATE"]
J --> K[Report + correction file]
Each entity requires an ImportDefinition<T> that declares importable properties
using a fluent API. Only explicitly declared properties are available for column
mapping (whitelist pattern).
When headers are extracted from the uploaded file, the mapping suggestion service
runs four tiers in order. Columns matched by a higher-confidence tier are excluded
from lower tiers:
After an import with SkipErrors or CollectAll, a downloadable CSV correction file
is generated. It contains only the failed rows with an additional error message column.
Users can fix the rows and re-upload the corrected file.
flowchart LR
A[Request export] --> B{Row count?}
B -- "threshold or less" --> C[Synchronous export]
B -- ">threshold" --> D[Background job]
C --> E[Query data source]
D --> E
E --> F[Project fields]
F --> G[Write CSV / Excel]
G --> H[Store blob]
H --> I[Download link]
.Field(p =>p.FirstName, f =>f.Header("First name"))
.Field(p =>p.Email)
.Field(p =>p.BirthDate, f => f
.Header("Date of birth")
.Format("dd/MM/yyyy"))
.Field(p =>p.Company, c =>c.Name, f =>f.Header("Company"));
}
}
Field configuration options:
Method
Description
.Header(string)
Column header name in the exported file
.Format(string)
Display format (e.g. "dd/MM/yyyy", "#,##0.00")
.Order(int)
Column order (lower values first)
Definition-level options:
Method
Description
.IncludeId()
Include entity Id column for roundtrip import compatibility
.IncludeBusinessKey()
Include business key columns from the matching import definition
Navigation fields use a two-argument Field() overload for dot-notation traversal.
The developer must ensure the corresponding Include() is present in the
IExportDataSource<T> implementation.
Presets are named field selections that users can save and reuse. They are stored
in the database via IExportPresetReader / IExportPresetWriter. The REST API
exposes CRUD operations under /metadata/presets/.
When QueryDefinitionName is set on an export definition, the export pipeline
delegates filtering and sorting to IQueryEngine<T> from Granit.Querying.
This reuses the same whitelist-based filtering pipeline as the grid view —
the user’s active filters are applied to the export.
All endpoints require authorization. Import endpoints use the
DataExchange.Imports.Execute permission, export endpoints use
DataExchange.Exports.Execute.
Without Wolverine, import and export commands dispatch via in-memory Channel<T> —
messages are lost on crash. Adding Granit.DataExchange.Wolverine replaces both
dispatchers with Wolverine’s IMessageBus for durable outbox-backed execution: