mirror of https://github.com/abpframework/abp.git
committed by
GitHub
12 changed files with 573 additions and 10 deletions
@ -0,0 +1,116 @@ |
|||
```json |
|||
//[doc-seo] |
|||
{ |
|||
"Description": "Import Excel or CSV data into ABP Low-Code pages with guided mapping, append or merge behavior, foreign-key matching, remote files, and invalid-row downloads." |
|||
} |
|||
``` |
|||
|
|||
# Data Import |
|||
|
|||
The React Low-Code runtime can import Excel and CSV files into a dynamic page. The import wizard previews the file in the browser, maps source columns to entity properties, reviews the operation, and sends the file plus the confirmed mapping to the backend. |
|||
|
|||
Import is enabled by default for pages and can be disabled per page with `importEnabled: false`. |
|||
|
|||
## Import Workflow |
|||
|
|||
1. Open a dynamic data page and select **Import**. |
|||
2. Upload an Excel or CSV file, or download a sample file for the page. |
|||
3. Review the detected columns and map each source column to one target property. |
|||
4. Choose **Append** or **Merge**. |
|||
5. Review required fields, conversions, relation matching, and file/image sources. |
|||
6. Run the import and download the invalid-row file if any rows fail. |
|||
|
|||
Column names are matched automatically when a source header equals a property name or display label after normalizing spaces, underscores, hyphens, dots, and letter casing. Review every automatic mapping before import. |
|||
|
|||
The wizard reports mappings as compatible, convertible, warning, or incompatible. The backend remains authoritative and validates each converted value, entity rule, and mapped property. |
|||
|
|||
## Append and Merge |
|||
|
|||
**Append** creates a new record for every valid row. The `Id` column is not accepted in append mode. |
|||
|
|||
**Merge** uses one mapped property as the match key: |
|||
|
|||
* A matching record is updated. |
|||
* A non-matching row creates a record. |
|||
* The match property must be included in the column mapping. |
|||
* When the selected property can match multiple records, choose either **Error** or **Use first**. **Use first** also requires a deterministic sort property and direction. |
|||
|
|||
Use an ID or unique business key whenever possible. A non-unique merge key makes the result depend on the selected multiple-match rule. |
|||
|
|||
## Foreign-Key Mapping |
|||
|
|||
A foreign-key column can contain the related record ID or another allowed match property such as a unique username or code. The wizard exposes the supported related-entity match fields for that property. |
|||
|
|||
If a foreign-key lookup can return multiple records, the same rules apply: |
|||
|
|||
* **Error** rejects the row. |
|||
* **Use first** requires an explicit sort property and direction. |
|||
|
|||
This decision is per mapped foreign-key column, independent of the main append or merge mode. |
|||
|
|||
## Value Extraction |
|||
|
|||
Use a source-value regular expression when a cell contains extra text around the value that should be imported. The expression must contain a named `value` capture group: |
|||
|
|||
```text |
|||
Order: (?<value>[A-Z]+-\d+) |
|||
``` |
|||
|
|||
The server compiles and executes the expression with bounded input, evaluation count, and elapsed-time budgets. A structurally valid client preview does not replace server validation. |
|||
|
|||
## File and Image URLs |
|||
|
|||
File and image properties can import remote files referenced by spreadsheet text. Source modes are: |
|||
|
|||
| Mode | Use it when | |
|||
|------|-------------| |
|||
| `auto` | The runtime should detect a supported URL shape | |
|||
| `fullUrl` | The whole cell is the URL | |
|||
| `fileNameAndUrl` | The cell contains a file name and URL | |
|||
| `extractUrlFromText` | The URL is embedded in surrounding text | |
|||
| `customRegex` | A custom expression extracts a named `url` group | |
|||
|
|||
Remote downloads are performed by the backend, not by the browser. The verified defaults require HTTPS on port `443`, allow only public network destinations, follow at most three redirects, and reject private, link-local, multicast, and loopback destinations. Development loopback HTTP is available only when both the environment is Development and `AllowLoopbackHttpInDevelopment` is enabled. |
|||
|
|||
Restrict production destinations with `LowCode:Import:RemoteFiles:AllowedHosts` when imports should fetch only from known hosts. Download count, per-file bytes, aggregate bytes, concurrency, redirects, and timeout are all bounded by `LowCode:Import:RemoteFiles` options. |
|||
|
|||
Remote files are staged before row persistence. A failed row or failed merge does not replace an existing stored file with an incomplete download. |
|||
|
|||
## Partial Failures |
|||
|
|||
Import continues after row-scoped validation or conversion failures. The result reports: |
|||
|
|||
* Total rows |
|||
* Succeeded and failed rows |
|||
* Created and updated records |
|||
* A short-lived invalid-row download token when failures exist |
|||
|
|||
The invalid-row file contains the original row values plus failure details so the rows can be corrected and imported again. The verified default token lifetime is 600 seconds. |
|||
|
|||
Failures that make the whole request unsafe, such as an invalid archive, exceeded global file budget, or blocked remote destination, stop the import before normal row processing. |
|||
|
|||
## Limits and Configuration |
|||
|
|||
Important verified defaults are: |
|||
|
|||
| Setting | Default | |
|||
|---------|---------| |
|||
| `LowCode:Import:MaxRows` | `10000` | |
|||
| `LowCode:Import:MaxColumns` | `256` | |
|||
| `LowCode:Import:InvalidRowsTokenLifetimeSeconds` | `600` | |
|||
| `LowCode:Import:RemoteFiles:Enabled` | `true` | |
|||
| `LowCode:Import:RemoteFiles:RequestTimeoutSeconds` | `15` | |
|||
| `LowCode:Import:RemoteFiles:MaxConcurrentDownloads` | `4` | |
|||
| `LowCode:Import:RemoteFiles:MaxFilesPerImport` | `500` | |
|||
| `LowCode:Import:RemoteFiles:MaxFileBytes` | `10485760` | |
|||
| `LowCode:Import:RemoteFiles:MaxTotalBytesPerImport` | `104857600` | |
|||
| `LowCode:Import:RemoteFiles:AllowedPorts` | `[443]` | |
|||
|
|||
The options validators reject non-positive, inconsistent, or above-ceiling values. Keep imports page-scoped and use the existing limits instead of accepting arbitrary workbook sizes. |
|||
|
|||
## See Also |
|||
|
|||
* [React Runtime](react-runtime.md) |
|||
* [Data Modeling and Page Behavior](data-modeling.md) |
|||
* [Model Descriptor Files](model-json.md) |
|||
* [Foreign Access](foreign-access.md) |
|||
@ -0,0 +1,248 @@ |
|||
```json |
|||
//[doc-seo] |
|||
{ |
|||
"Description": "Model Low-Code property storage, primitive collections, related fields, presentations, backend filters, and page or relationship permissions." |
|||
} |
|||
``` |
|||
|
|||
# Data Modeling and Page Behavior |
|||
|
|||
The Low-Code Designer can model more than scalar fields and basic CRUD pages. This page covers the data and page features that affect storage, queries, presentation, and authorization. |
|||
|
|||
## Property Storage |
|||
|
|||
Scalar properties use one of two storage shapes: |
|||
|
|||
* `isMappedToDbField: true` maps the property to its own physical column. |
|||
* An omitted or `false` `isMappedToDbField` stores the property through the entity's dynamic data mapping. |
|||
|
|||
By default, dynamic data mapping uses the entity's JSON `Data` column. Applications that need individual columns for those properties can disable JSON data storage while configuring EF Core: |
|||
|
|||
```csharp |
|||
builder.ConfigureDynamicEntities(useJsonDataStorage: false); |
|||
``` |
|||
|
|||
The equivalent module option is `AbpLowCodeEntityFrameworkCoreOptions.UseJsonDataStorage`. Its verified default is `true`. |
|||
|
|||
Changing the storage mode or `isMappedToDbField` affects the physical schema. Decide the storage strategy before creating production tables, then use the normal migration or runtime schema workflow for later changes. Formulas and rollups are virtual and do not create physical scalar columns. |
|||
|
|||
Source-model and runtime-model dynamic tables can use separate prefixes: |
|||
|
|||
```csharp |
|||
LowCodeDbProperties.JsonModelTablePrefix = "Src_"; |
|||
LowCodeDbProperties.RuntimeTablePrefix = "Runtime_"; |
|||
``` |
|||
|
|||
Configure prefixes before the dynamic model is initialized. Changing a prefix after tables exist requires renaming or migrating those tables. |
|||
|
|||
## Primitive Collections |
|||
|
|||
A primitive collection keeps an ordered list of values on one property. Supported element types are `string`, `int`, `long`, `decimal`, `dateTime`, `boolean`, `guid`, `enum`, `date`, `time`, `money`, `file`, and `image`. |
|||
|
|||
```json |
|||
{ |
|||
"name": "Tags", |
|||
"type": "string", |
|||
"collection": { |
|||
"maxCount": 25, |
|||
"uniqueItems": true, |
|||
"storageKey": "b7db3ad2-3452-511b-b9b7-cc11d2db6dcb" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
Collection rules: |
|||
|
|||
* `maxCount` is optional, but must be greater than zero when supplied. |
|||
* `uniqueItems` is required and controls duplicate-value validation. |
|||
* The effective item limit is the lower of `maxCount` and `LowCode:PrimitiveCollections:MaximumItemsPerProperty`. The verified global default is `1000`. |
|||
* `storageKey` is a stable internal identity used by the normalized collection table. Let the Designer generate it and do not change it after data exists. |
|||
* A collection property cannot also be a foreign key, formula, or rollup. |
|||
|
|||
Collections are stored in normalized rows rather than inside the owner JSON payload. The React runtime returns them as ordered arrays and uses collection-aware controls for scalar, enum, file, and image values. |
|||
|
|||
## Related Fields and Self-Relations |
|||
|
|||
Page columns and filters can follow foreign keys by using dot-separated property paths: |
|||
|
|||
```json |
|||
{ |
|||
"columns": [ |
|||
{ "propertyName": "CustomerId.Name", "label": "Customer" }, |
|||
{ "propertyName": "CustomerId.CountryId.Name", "label": "Country" } |
|||
], |
|||
"filters": [ |
|||
{ "propertyName": "CustomerId.CountryId.RegionId.Name" } |
|||
] |
|||
} |
|||
``` |
|||
|
|||
Only requested related fields are projected into the response. The same paths can be used by page filtering and export, including registered reference entities. |
|||
|
|||
Self-relations are supported. For example, an employee page can use `ManagerId.ManagerId.Name` to follow the same relation more than once. Every path is still limited by the configured maximum foreign-key depth exposed by the Low-Code query capabilities. |
|||
|
|||
## Reverse Relationships |
|||
|
|||
A foreign key defines the schema direction. A page relationship defines how records that point back to the host record are shown and edited: |
|||
|
|||
```json |
|||
{ |
|||
"name": "Authors", |
|||
"entityName": "Acme.Authors.Author", |
|||
"relationships": [ |
|||
{ |
|||
"id": "author-books", |
|||
"sourceEntityName": "Acme.Books.Book", |
|||
"sourcePropertyName": "AuthorId", |
|||
"access": "edit", |
|||
"relatedPageMode": "page", |
|||
"relatedPageName": "Books", |
|||
"createFormMode": "generated", |
|||
"editFormMode": "form", |
|||
"editFormName": "BookEditForAuthor" |
|||
} |
|||
] |
|||
} |
|||
``` |
|||
|
|||
`access` can be `none`, `view`, or `edit`. The generated modes build the related page or form from the source entity; the explicit modes reuse named page and form descriptors. |
|||
|
|||
See [Foreign Access](foreign-access.md) for the runtime APIs and UI behavior used by these relationships. |
|||
|
|||
## Enum and Boolean Presentation |
|||
|
|||
Enum values can define reusable display metadata: |
|||
|
|||
```json |
|||
{ |
|||
"name": "Acme.Orders.OrderStatus", |
|||
"values": [ |
|||
{ |
|||
"name": "Pending", |
|||
"value": 10, |
|||
"displayName": "Waiting", |
|||
"presentation": "badge", |
|||
"color": "#F59E0B" |
|||
} |
|||
] |
|||
} |
|||
``` |
|||
|
|||
Enum presentation supports `text`, `badge`, and `iconOnly`. Pages can override the display name, presentation, color, or icon for one property without changing the shared enum: |
|||
|
|||
```json |
|||
{ |
|||
"enumPresentations": [ |
|||
{ |
|||
"propertyName": "Status", |
|||
"values": [ |
|||
{ "value": 10, "displayName": "Awaiting review", "presentation": "badge", "color": "#F59E0B" } |
|||
] |
|||
} |
|||
] |
|||
} |
|||
``` |
|||
|
|||
Boolean columns support `text`, `checkbox`, `badge`, and `iconOnly`, with separate metadata for `true`, `false`, and `null`: |
|||
|
|||
```json |
|||
{ |
|||
"propertyName": "IsActive", |
|||
"booleanPresentation": "badge", |
|||
"booleanValues": { |
|||
"true": { "displayName": "Active", "color": "#16A34A" }, |
|||
"false": { "displayName": "Inactive", "color": "#DC2626" }, |
|||
"null": { "displayName": "Not set", "color": "#6B7280" } |
|||
} |
|||
} |
|||
``` |
|||
|
|||
Icons can reference a CSS class, stored blob, data URL, or application path. Runtime-layer writes apply stricter icon validation than source-controlled descriptors. |
|||
|
|||
## Backend Filters |
|||
|
|||
Visible page filters are controlled by the user. A backend filter is always applied by the server and is useful for tenant, ownership, role, or workflow scoping. |
|||
|
|||
```json |
|||
{ |
|||
"backendFilter": { |
|||
"items": [ |
|||
{ |
|||
"propertyName": "Status", |
|||
"operator": "equal", |
|||
"value": "Active" |
|||
}, |
|||
{ |
|||
"logic": "or", |
|||
"items": [ |
|||
{ |
|||
"propertyName": "CreatorId", |
|||
"operator": "equal", |
|||
"valueProvider": "CurrentUserId" |
|||
}, |
|||
{ |
|||
"logic": "and", |
|||
"propertyName": "AllowedRole", |
|||
"operator": "in", |
|||
"valueProvider": "CurrentUserRoles" |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
} |
|||
``` |
|||
|
|||
A filter value can be: |
|||
|
|||
* Static through `value`. |
|||
* Resolved by JavaScript through `javaScript`. |
|||
* Resolved by a registered provider through `valueProvider`. |
|||
|
|||
Built-in providers cover the current user ID, username, first name, surname, email, email verification, phone number, phone verification, roles, and current tenant ID. Applications can register additional typed providers with `AbpLowCodePageBackendFilterOptions`. |
|||
|
|||
Backend filters are combined with search and user-selected filters. They are not sent as editable client state, so do not replace them with a hidden React filter when the rule is security-sensitive. |
|||
|
|||
## Page and Relationship Permissions |
|||
|
|||
Pages use resource-based authorization by default. `permissionConfig` can keep that generated default, require a named permission, allow any authenticated user, or make an operation public: |
|||
|
|||
```json |
|||
{ |
|||
"permissionConfig": { |
|||
"view": "default", |
|||
"create": "Acme.Orders.Create", |
|||
"update": "authenticated", |
|||
"delete": "Acme.Orders.Delete" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
For generated reverse relationships, enable separate authorization when child access must not inherit the host page decision: |
|||
|
|||
```json |
|||
{ |
|||
"id": "author-books", |
|||
"sourceEntityName": "Acme.Books.Book", |
|||
"sourcePropertyName": "AuthorId", |
|||
"access": "edit", |
|||
"useSeparatePermission": true, |
|||
"permissionConfig": { |
|||
"view": "default", |
|||
"create": "Acme.Books.Create", |
|||
"update": "Acme.Books.Update", |
|||
"delete": "Acme.Books.Delete" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
When `useSeparatePermission` is `true`, generated relationship permissions are scoped to the host page and relationship ID. Create, update, and delete also require relationship view access. |
|||
|
|||
## See Also |
|||
|
|||
* [Low-Code Designer](designer.md) |
|||
* [Model Descriptor Files](model-json.md) |
|||
* [Calculated and Rollup Properties](formula-properties.md) |
|||
* [Data Import](data-import.md) |
|||
* [Foreign Access](foreign-access.md) |
|||
* [React Runtime](react-runtime.md) |
|||
@ -0,0 +1,111 @@ |
|||
```json |
|||
//[doc-seo] |
|||
{ |
|||
"Description": "Use ABP Low-Code runtime model history, undo and redo, save points, comparison, safe entity deletion, and retained-data restoration." |
|||
} |
|||
``` |
|||
|
|||
# Model History and Recovery |
|||
|
|||
The Low-Code Designer records applied mutation batches for history-enabled writable layers. In the standard setup, the history controls operate on the **Runtime JSON** layer. Source-controlled descriptor changes continue to use Git and the normal migration workflow. |
|||
|
|||
The Designer toolbar exposes **Undo history**, **Redo history**, and **History** when the selected layer supports these operations. |
|||
|
|||
## History Batches |
|||
|
|||
Each successful model write is recorded as a batch with: |
|||
|
|||
* Sequence and creation information |
|||
* Forward and inverse operations |
|||
* Before and after concurrency stamps |
|||
* Checkpoints within the operation list |
|||
* Status, source kind, and schema-impact metadata |
|||
|
|||
History is model history, not record audit history. It tracks changes to entities, pages, forms, permissions, scripts, and other descriptors; it does not list CRUD changes made to business records. |
|||
|
|||
The history list is paged independently from the save-point list. The verified defaults keep up to 200 history batches and 100 save points per runtime layer. Retention can be changed through `LowCodeRuntimeHistoryOptions`. |
|||
|
|||
## Undo, Redo, and Targeted Actions |
|||
|
|||
Available history actions are: |
|||
|
|||
| Action | Purpose | |
|||
|--------|---------| |
|||
| Undo | Apply the inverse of the current applied batch | |
|||
| Redo | Reapply the next undone batch | |
|||
| Go to checkpoint | Move the history cursor to a before/after checkpoint | |
|||
| Revert range | Revert a selected range of batches | |
|||
| Go to save point | Move through retained history to the save point cursor | |
|||
| Restore save point | Restore the full model snapshot saved at that point | |
|||
| Apply operation | Apply one selected operation from a history batch | |
|||
|
|||
Use **Go to save point** when its history cursor is still available. Use **Restore save point** when the exact cursor is no longer retained or when the saved snapshot is the intended source of truth. |
|||
|
|||
## Preview Before Apply |
|||
|
|||
Every history action can be previewed before it writes. The preview reports: |
|||
|
|||
* Whether the action is valid |
|||
* Current concurrency stamp and conflicts |
|||
* Ordered operations |
|||
* Schema impact |
|||
* Whether destructive schema confirmation is required |
|||
* Warnings and structured conflicts |
|||
|
|||
Apply the action with the same current concurrency stamp used by the reviewed preview. If the model changes between preview and apply, refresh history and preview again. |
|||
|
|||
History actions do not drop physical tables or columns by default. When a preview reports destructive schema impact, the apply request requires explicit destructive confirmation. Review the affected operations and data-loss impact before enabling it. |
|||
|
|||
## Save Points and Compare |
|||
|
|||
A save point stores a named model snapshot plus its history cursor. Create one before a coordinated set of runtime changes or before a risky schema edit. |
|||
|
|||
History comparison can compare current, save-point, before-save, after-save, and operation-checkpoint states. The result contains forward and inverse operations and reports both general and destructive schema impact without changing the model. |
|||
|
|||
Comparison and history actions are protected by entry, operation, and serialized-payload budgets. Old history can be pruned while a save point retains its snapshot for later comparison or restore. |
|||
|
|||
## Safe Entity Deletion |
|||
|
|||
Entity deletion is a planned operation. Before the Designer deletes an entity, it builds a plan containing: |
|||
|
|||
* Descriptors that will be removed with it |
|||
* Relationships that need resolution |
|||
* Blocking references |
|||
* Affected physical tables |
|||
* Whether each table is Designer-managed or migration-managed |
|||
* Current concurrency stamp and a plan fingerprint |
|||
|
|||
For each resolvable relationship, choose one of the actions offered by the plan, such as removing the source property or converting it to a scalar. The apply step rejects stale plans and unreviewed relationship decisions. |
|||
|
|||
Designer-managed tables require an explicit data choice: |
|||
|
|||
* **Keep physical data** removes the model descriptors while retaining the physical table and its file, image, attachment, and collection data. |
|||
* **Delete physical data** drops eligible physical tables and deletes their associated stored data. |
|||
|
|||
Migration-managed entities cannot be physically dropped by the runtime Designer. Their plan requires the migration path to be acknowledged instead. |
|||
|
|||
## Restore Retained Entity Data |
|||
|
|||
When an entity was deleted with **Keep physical data**, the Designer can preview and restore its retained table. The preview reports the table, row count, property shape, retained physical object ID, schema fingerprint, and current concurrency stamp. |
|||
|
|||
Restore only from a fresh preview. The apply request must repeat its exact: |
|||
|
|||
* `retainedPhysicalObjectId` |
|||
* `schemaFingerprint` |
|||
* `concurrencyStamp` |
|||
|
|||
The server rejects a stale concurrency stamp, changed schema, mismatched retained object, or already-restored table. A successful restore recreates the entity descriptor against the retained physical data instead of copying the rows into a new table. |
|||
|
|||
Keeping physical data is not a backup strategy. Retention metadata remains part of the same application database and should be covered by the application's normal backup and recovery process. |
|||
|
|||
## MCP Automation |
|||
|
|||
The runtime-only [MCP Integration](mcp.md) exposes the same history, comparison, formula/rollup, safe-deletion, and retained-restore service workflows. MCP clients should follow the feature semantics on this page, preview destructive operations, preserve concurrency stamps, and re-read [Health](health.md) after apply. |
|||
|
|||
## See Also |
|||
|
|||
* [Low-Code Designer](designer.md) |
|||
* [Health](health.md) |
|||
* [MCP Integration](mcp.md) |
|||
* [Model Descriptor Files](model-json.md) |
|||
* [Calculated and Rollup Properties](formula-properties.md) |
|||
Loading…
Reference in new issue