4.2 Data Modification & the Write to Data Store Entity Smart Service
Key Takeaways
For a generated primary key, omit the identifier for a new row and supply the existing identifier for an update; use the supported mapping for other key strategies.
Capturing the Stored Values output (AC!StoredValues) back into a process variable is mandatory when inserting records with database-generated primary keys to make the new IDs available to downstream workflow nodes.
The smart service can process single CDT instances or arrays of CDTs, executing bulk multi-row database operations within a single atomic transaction.
a!writeToDataStoreEntity() allows synchronous database writes directly from SAIL interface save parameters, but complex multi-step orchestrations, document generation, and integrations belong in Process Models.
Choose soft deletion, hard deletion, and audit retention according to the application requirements; a status flag alone does not guarantee compliance.
4.2 Data Modification & the Write to Data Store Entity Smart Service
The Write to Data Store Entity Smart Service in Process Models
In Appian enterprise architecture, modifying relational data is primarily executed through the Write to Data Store Entity smart service node within Process Models. Unlike simple script tasks that manipulate variables in memory, this smart service opens a transactional database connection through the Java Persistence API (JPA) layer, evaluates data modifications, and commits them to the physical relational database schema.
As an unattended system smart service, it is placed along workflow paths after user forms, validation rules, or system integrations. When configured with activity chaining, the database write occurs seamlessly between human tasks without interrupting the user's interface flow, ensuring immediate data consistency.
Configuring Node Inputs: Data Store Entity and Values to Store
The Write to Data Store Entity smart service is configured through the Data tab of the node properties window:
+-----------------------------------------------------------------------------------+
| Node Properties: Write to Data Store Entity |
+-----------------------------------------------------------------------------------+
| [General] [Data] [Scheduling] [Assignment] |
+-----------------------------------------------------------------------------------+
| Inputs: |
| * Data Store Entity (DataStoreEntity) -> cons!PURCHASE_ORDER_DSE |
| * Values to Store (Any Type) -> pv!purchaseOrder |
+-----------------------------------------------------------------------------------+
| Outputs: |
| * Stored Values (AC!StoredValues) -> pv!purchaseOrder |
+-----------------------------------------------------------------------------------+
Required Inputs
- Data Store Entity: The specific DSE pointer representing the target database table (typically assigned via a constant such as
cons!PURCHASE_ORDER_DSE). - Values to Store: The process variable containing the data to persist. This input accepts either:
- A Single CDT Instance: Writes or updates one specific row (e.g.,
pv!customerof typeCustomer). - An Array / List of CDTs: Writes or updates multiple rows in a single batch operation (e.g.,
pv!orderItemsof typeList of OrderItem).
- A Single CDT Instance: Writes or updates one specific row (e.g.,
Single vs. Batch Array Writes
When an array of CDTs is supplied to Values to Store, Appian executes a batch JDBC write within a single database transaction. This is substantially faster than looping through a process model with a single-item write node, which incurs individual transaction overhead, process engine transitions, and connection handshakes for each record.
Node Outputs: The Critical Role of Stored Values (AC!StoredValues)
A fundamental concept on the Associate Developer exam is the role of the node's Outputs tab. When a new entity record is inserted into a database table configured with an auto-incrementing primary key (annotated with @GeneratedValue), the primary key field in the incoming process variable is initially null or 0.
When the Write to Data Store Entity node completes the SQL INSERT, the relational database engine generates the next sequence value (e.g., 10492). Appian captures this newly generated identifier and returns the updated, complete CDT via the activity class output variable AC!StoredValues.
| Execution Step | Value of pv!order.orderId | Database Action | Purpose |
|---|---|---|---|
| 1. Before Node Execution | null | None | Order CDT populated in user form without primary key. |
| 2. During Node Execution | null | INSERT INTO orders ... | Database generates auto-increment key 10492. |
| 3. Output Mapping | AC!StoredValues.orderId = 10492 | Committed | AC!StoredValues mapped back into pv!order. |
| 4. Downstream Nodes | 10492 | Available | Child line items can now use pv!order.orderId as foreign key. |
Important
If a developer omits the Stored Values output mapping on a node that inserts parent records, the parent process variable will still contain null for its primary key. Any downstream nodes attempting to write child records will fail to associate foreign keys, leading to orphaned records or database constraint violations.
SQL Generation Mechanics: Primary Key Dictates INSERT vs. UPDATE
The Write to Data Store Entity smart service automatically deduces whether to execute an SQL INSERT or an SQL UPDATE statement by inspecting the primary key field of the CDT being passed to Values to Store:
Detailed Persistence Behavior
- Insert Operation: If the primary key field (annotated with
@Id) isnull for a database-generated key, the persistence engine generates anINSERT INTO table_name (...) VALUES (...)` statement. - Update Operation: If the primary key field contains an existing identifier (e.g.,
orderId = 502), the engine generates anUPDATE table_name SET ... WHERE order_id = 502.
The Partial Update Hazard (Overwriting with Nulls)
A common trap arises when developers attempt to update only one or two fields on an existing record. In Appian's ORM model, the smart service updates the entire row matching the primary key. If a developer initializes a brand-new CDT in a script task, sets orderId = 502 and status = "APPROVED", but leaves customer name, order total, and order date empty, the smart service will overwrite those existing database columns with NULL!
Best Practice for Updates: Always query the existing record from the database first using a!queryEntity(), update only the specific fields requiring modification in memory (using update() or dot notation), and then pass the complete, modified CDT to the Write to Data Store Entity node.
Deleting Data: Delete from Data Store Entities vs. Soft-Delete Patterns
When business records are no longer needed, Appian provides two distinct technical strategies: hard deletion and soft deletion.
1. Hard Deletes: The Delete from Data Store Entities Smart Service
Appian includes a dedicated smart service node: Delete from Data Store Entities. Developers configure:
- The target Data Store Entity.
- EntityDataIdentifiers values constructed with the entity and an array of primary-key identifiers. Do not pass CDT instances as identifiers.
The database executes physical DELETE FROM table WHERE id IN (...) statements.
- Pros: Completely frees storage space in the database.
- Risks: If other tables contain foreign keys referencing these records without cascading delete rules, the database will throw a foreign key constraint violation, pausing the process model with an alert. Furthermore, physical deletion destroys historical audit trails.
2. Soft Deletes and Retention Requirements
Choose retention and deletion according to the actual requirements. One option is a soft-delete pattern using a status indicator field on the CDT (e.g., isActive of type Boolean, or recordStatus of type Text):
- To "delete" a record, the application updates the record using Write to Data Store Entity, setting
isActive = falseorrecordStatus = "DELETED"alongside a timestamp and user ID. - All interface queries and reports filter by
isActive = true. - Advantages: Preserves complete historical auditability, supports the application's historical reporting requirements when used with an appropriate retention policy, and prevents broken foreign key relationships across reporting warehouses.
Interface-Level Persistence: a!writeToDataStoreEntity() in SAIL
In addition to process models, Appian provides an expression function for persisting data directly from SAIL interfaces: a!writeToDataStoreEntity(). This function is designed for execution within interface event handlers, such as the saveInto parameter of an a!buttonWidget():
a!buttonWidget(
label: "Save Draft",
value: true,
saveInto: {
a!writeToDataStoreEntity(
dataStoreEntity: cons!DRAFT_APPLICATION_DSE,
valueToStore: local!applicationData,
onSuccess: {
a!save(local!applicationData, fv!storedValues),
a!save(local!saveMessage, "Draft saved successfully at " & now())
},
onError: {
a!save(local!errorMessage, "The draft could not be saved. Please retry after the issue is resolved.")
}
)
}
)
Architectural Trade-offs: SAIL Writes vs. Process Models
While a!writeToDataStoreEntity() provides instantaneous interface feedback without starting a process instance, developers must carefully evaluate architectural boundaries:
| Criteria | a!writeToDataStoreEntity() (SAIL) | Write to Data Store Entity (Process Model) |
|---|---|---|
| Execution Context | Triggered in an interface save context; handle success and error callbacks. | Asynchronous or activity-chained in process engine. |
| Orchestration Scope | Limited to direct database persistence. | Can orchestrate multi-system writes, generate PDF/Excel docs, send emails, and branch dynamically. |
| Error Handling | Local onError save parameter handling. | System administrator alert routing, process pause, manual task reassignment, and compensable retries. |
| Audit History | Minimal; requires manual logging into audit tables. | Full process execution history and process variable timeline preserved automatically. |
| Best Use Case | Quick inline autosave, drafting, or simple single-table interface actions. | Enterprise transactions, order intake, regulatory approvals, and multi-entity workflows. |
Real-World Scenario: Global Supply Chain Purchase Order Fulfillment
A global retail enterprise operates a warehouse fulfillment portal. When a shipping container arrives, a logistics manager verifies 40 distinct items. The intake process model must:
- Insert a new
Shipmentparent record. - Receive the database-generated
shipmentId. - Assign that
shipmentIdto all 40 childShipmentItemrecords. - Persist the array of 40 child items to the database.
During initial deployment, the junior developer failed to map AC!StoredValues on the first Write to Data Store Entity node. When the process ran, pv!shipment.shipmentId remained null. The second write node attempted to insert 40 child items with foreign key shipmentId = null. The database immediately threw a NOT NULL constraint exception, failing the shipment intake and alerting the on-call administrator.
The fix was simple: on the first node's Data tab, the developer mapped AC!StoredValues back into pv!shipment. With pv!shipment.shipmentId populated, a subsequent script task mapped the generated ID across the item array using a!forEach(), allowing the child rows to reference the generated parent identifier. Verify the saved rows rather than assuming a fixed execution time.
Exam Watchouts & Common Traps
- Missing Stored Values Mapping: An important development scenario involves an auto-generated primary key failing to pass to child records. Remember: you must map
AC!StoredValuesback to the process variable to capture database-generated IDs. - Passing Untyped Data:
Values to Storeexpects a CDT or an array of CDTs matching the Data Store Entity definition. Passing an untyped dictionary or an incompatible CDT will result in a runtime casting error. - Data Store Security Permissions: The user initiating the process (or the custom process model execution credentials) must possess at least Viewer permissions on the underlying Data Store design object. Lacking Viewer rights triggers an immediate security authorization failure at runtime.
- Full Row Overwrites: Passing a partially populated CDT with an existing primary key overwrites all omitted columns with
null. To update partial data, always query the full record first before applying changes.
Source checked 2026-10-18: Appian write to data store.
In an Appian process model, how does the Write to Data Store Entity smart service determine whether to execute a SQL INSERT statement or a SQL UPDATE statement against the database table?
By checking whether the process model was triggered by an interface action or an incoming webhook
By evaluating whether the process variable is marked as a hidden or required parameter
By inspecting an explicit dropdown setting on the Data tab named "Operation Type"
By evaluating whether the Custom Data Type's primary key field is null for a generated key (INSERT) or populated with an existing identifier (UPDATE)
A developer configures a process model to create a new customer record and subsequently create three contact records associated with that customer. After the Write to Data Store Entity node executes for the customer, the contact records are written with null foreign keys. What configuration step was omitted in the customer write node?
Saving the Stored Values output (AC!StoredValues) back into the customer process variable to capture the database-generated primary key
Adding an activity chaining loop back to the Start Node
Checking the "Force Synchronous Execution" checkbox on the General tab
Changing the customer CDT data type to an untyped dictionary
An application requires a multi-step user onboarding workflow that writes user data to a database, generates an official PDF welcome letter, calls an external REST API to provision corporate credentials, and alerts a manager if any step fails. Why should this implementation use a Process Model rather than a!writeToDataStoreEntity() in a SAIL interface?
SAIL interfaces cannot write data to relational databases under any circumstances
Process models execute faster than interface expressions by bypassing database validation constraints
Process models provide multi-step orchestration with document-generation services, integrations, and configurable error-handling paths
The a!writeToDataStoreEntity() function can only write data to external cloud storage rather than relational tables
Sections you finish are checked off in the contents.