filesoft.Discuss a project
← Practical FileMaker guides

PRACTICAL FILEMAKER GUIDES

Save related FileMaker records together with a transaction

Plan a parent-and-two-lines write with explicit commit, revert and result checks, then exercise success and failure in a practice file.

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.

RecordDescriptionQuantity
RequestPractice supply request—
Line 1Notebooks2
Line 2Folders3

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 ↓

CaseDatabase resultCaller result
Two valid lines1 parent + 2 linked childrenSuccess after commit
Invalid second line after earlier writesNo records from this attemptFailure
Commit validation failureNo partial requestFailure
Another intentional valid callAnother parent + 2 new childrenSuccess
Existing transaction before callNo writes by this operationReject 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.