1. Define one complete change
A request with two lines should not be saved with only its first line. Group the database writes and define the outcome: one parent and two children, or none of the new records.
This intermediate desktop exercise uses transaction steps introduced in FileMaker Pro 19.6.1. Use one window in a separate practice file. The overview explains the control flow; the complete practice script below names the steps and options to recreate in Script Workspace.
Start without unsaved user edits. Opening a transaction may first commit the active record; it does not retroactively make earlier edits reversible.
2. Prepare the IDs and table contexts
Create Requests with RequestID and Title (Text). Create RequestLines with LineID, RequestID and Description (Text), and Quantity (Number). Use unique, nonblank record IDs. Relate the tables by RequestID and provide a simple layout for each occurrence.
Generate a request ID into a variable before creating records. Explicitly set it into the parent and both children; generate a separate ID for each line. Do not depend on a deferred auto-enter value to establish these links.
| Record | Description | Quantity |
|---|---|---|
| Request | Practice supply request | — |
| Line 1 | Notebooks | 2 |
| Line 2 | Folders | 3 |
Define required IDs and positive-quantity validation in the schema as well as checking script inputs. Keep validation enabled. An invalid-second-line test must fail after earlier writes to demonstrate rollback rather than just preflight rejection.
3. Put the writes inside the transaction
Prepare → Open → Write request + both lines → Commit
Failed write or invalid line → Revert → Return failure
Implement this algorithm with your actual layouts and fields. Keep all steps in the originating window.
Before starting
Reject invalid inputs and an unexpected open transaction.
Prepare request ID and two line IDs.
Enable error capture; keep validation enabled.
Open Transaction
Confirm opening succeeded before writing.
Go to Requests; create request; set its fields.
Capture the error immediately after each fallible step.
On failure, revert with a clear failure code.
Go to RequestLines in the same window.
Create Line 1 and explicitly set its parent ID and fields.
Check each step; revert on failure.
Create Line 2 and set its parent ID and fields.
Reject a non-positive quantity; revert on failure.
Commit Transaction
Immediately capture the final transaction error.
Return success only if commit succeeded.
Otherwise return the preserved failure result.This is an algorithm, not executable FileMaker syntax. Use the error-handling guide for immediate error capture. Do not change layouts again before reading the final error.
4. Check the commit outcome
A flag set after the parent was created does not prove its children were saved. Report success only after checking the commit outcome. Preserve the failing operation as well as its error so the caller can explain the problem.
Revert Transaction skips to the paired Commit Transaction. Put final outcome handling after that paired step instead of relying on steps immediately after Revert. Review the documented control flow when implementing the script.
A commit can fail validation even if the earlier steps looked successful. Keep that failure visible rather than disabling the validation rule.
5. Prove both outcomes
Download the transaction cases ↓
Download the implementation checklist ↓
| Case | Database result | Caller result |
|---|---|---|
| Two valid lines | 1 parent + 2 linked children | Success after commit |
| Invalid second line after earlier writes | No records from this attempt | Failure |
| Commit validation failure | No partial request | Failure |
| Another intentional valid call | Another parent + 2 new children | Success |
| Existing transaction before call | No writes by this operation | Reject before opening |
Record table counts before each case. After failure, find the attempted RequestID in both tables and check it is absent; existing unrelated records should remain. After success, inspect both child keys and reopen the file to verify persistence.
A second successful invocation intentionally creates another request here. Preventing an accidental retry from creating duplicates needs an idempotency policy. Atomicity alone does not provide one.
6. State the limits of rollback
An email already sent or an HTTP request accepted elsewhere cannot be recalled by reverting these records. Plan external work after successful commit and give it separate retry handling.
Keep window changes, management dialogs and maintenance actions outside this exercise. Read the transaction restrictions before extending it. Test with the intended privileges and triggers.
Finished result: an all-or-nothing write demonstrated with an invalid second line as well as valid data. Native execution of your implementation is the verification; the outline alone is not that proof.
FileMaker script example
Use FileMaker Pro 19.6.1 or later. Create Requests and RequestLines layouts on the occurrences named above. Configure required, unique IDs and positive Quantity validation with no override; keep all Open Transaction skip options off. Use no triggers or auto-enter rules beyond the stated fixture. Keep this script in one window and do not call it inside another transaction.
Pass valid or invalid-second-line. The latter deliberately reaches the second child before rejection so the test can prove that earlier writes roll back. It is a controlled failure fixture, not a production rule that accepts invalid inputs.
How to use this: recreate the steps and their options in Script Workspace. This is readable script text, not a clipboard snippet or an importable script. These examples have been checked against documentation but have not been executed in a native FileMaker file.
Recreate these steps
FileMaker script
# Requests | Create two practice lines
Set Error Capture [ On ]
If [ Get ( WindowMode ) ≠ 0 or Get ( RecordOpenState ) ≠ 0 or Get ( TransactionOpenState ) ]
Exit Script [ Text Result: "blocked: finish the edit or transaction" ]
End If
Set Variable [ $case ; Value: Get ( ScriptParameter ) ]
If [ $case ≠ "valid" and $case ≠ "invalid-second-line" ]
Exit Script [ Text Result: "invalid_test_case" ]
End If
Set Variable [ $requestId ; Value: Get ( UUID ) ]
Set Variable [ $error ; Value: 0 ]
Open Transaction [ ]
Loop
Go to Layout [ "Requests" (Requests) ; Animation: None ]
Set Variable [ $error ; Value: Get ( LastError ) ]
Exit Loop If [ $error ≠ 0 ]
New Record/Request
Set Variable [ $error ; Value: Get ( LastError ) ]
Exit Loop If [ $error ≠ 0 ]
Set Field [ Requests::RequestID ; $requestId ]
Set Variable [ $error ; Value: Get ( LastError ) ]
Exit Loop If [ $error ≠ 0 ]
Set Field [ Requests::Title ; "Practice supply request" ]
Set Variable [ $error ; Value: Get ( LastError ) ]
Exit Loop If [ $error ≠ 0 ]
Go to Layout [ "RequestLines" (RequestLines) ; Animation: None ]
Set Variable [ $error ; Value: Get ( LastError ) ]
Exit Loop If [ $error ≠ 0 ]
Set Variable [ $i ; Value: 1 ]
Loop
New Record/Request
Set Variable [ $error ; Value: Get ( LastError ) ]
Exit Loop If [ $error ≠ 0 ]
Set Field [ RequestLines::LineID ; Get ( UUID ) ]
Set Variable [ $error ; Value: Get ( LastError ) ]
Exit Loop If [ $error ≠ 0 ]
Set Field [ RequestLines::RequestID ; $requestId ]
Set Variable [ $error ; Value: Get ( LastError ) ]
Exit Loop If [ $error ≠ 0 ]
Set Field [ RequestLines::Description ; If ( $i = 1 ; "Notebooks" ; "Folders" ) ]
Set Variable [ $error ; Value: Get ( LastError ) ]
Exit Loop If [ $error ≠ 0 ]
Set Field [ RequestLines::Quantity ; If ( $i = 1 ; 2 ; If ( $case = "invalid-second-line" ; 0 ; 3 ) ) ]
Set Variable [ $error ; Value: Get ( LastError ) ]
Exit Loop If [ $error ≠ 0 ]
If [ RequestLines::Quantity ≤ 0 ]
Set Variable [ $error ; Value: 5002 ]
Exit Loop If [ 1 ]
End If
Set Variable [ $i ; Value: $i + 1 ]
Exit Loop If [ $i > 2 ]
End Loop
Exit Loop If [ 1 ]
End Loop
If [ $error ≠ 0 ]
Revert Transaction [ Condition: True ; Error Code: 5001 ; Error Message: "Practice write rejected" ]
End If
Commit Transaction
Set Variable [ $transactionError ; Value: Get ( LastError ) ]
Exit Script [ Text Result: JSONSetElement ( "{}" ;
[ "status" ; If ( $transactionError = 0 and $error = 0 ; "saved" ; "error" ) ; JSONString ] ;
[ "requestId" ; $requestId ; JSONString ] ;
[ "transactionError" ; $transactionError ; JSONNumber ] ;
[ "stepError" ; $error ; JSONNumber ] ) ]Claris documents that Revert Transaction jumps to the matching Commit Transaction. Read the final error immediately after that boundary. An automatic validation rollback may also skip the remaining write steps; in that case transactionError is the decisive failure signal and stepError may still be zero. Code 5001 is this example’s explicit rollback code; 5002 is its local quantity-check result.
After valid, find the returned RequestID in both tables: one request and two children, quantities 2 and 3. After invalid-second-line, that ID must be absent from both tables. Existing records must be unchanged. Repeat with a schema-validation failure at commit. A second valid call creates a new request; this example does not implement idempotency.
References
Use a practice copy and verify the result in your FileMaker version. Product requirements and platform support remain specific to each product.
Filesoft counts page loads and selected resource and practice-download clicks in aggregate. These aggregate counts contain no practice data or visitor identifiers. Browser privacy signals and the site’s analytics-off preference disable these counts.