Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ This activity can be used in both microflows and nanoflows.

## Introduction

The **Commit object(s)** activity works on one or more objects. For persistable entities, committing an object stores it in the database. Committing non-persistable entities stores the current attribute values and association values in memory. This allows a rollback to revert to those values. See also [Persistability](/refguide/persistability/). External objects cannot be committed. To store changed values of external objects, use the [Send External Object](/refguide/send-external-object/) activity.
The **Commit object(s)** activity works on one or more objects. For persistable entities, committing an object writes it to the database. Committing non-persistable entities stores the current attribute values and association values in memory. This allows a rollback to revert to those values. See also [Persistability](/refguide/persistability/). External objects cannot be committed. To store changed values of external objects, use the [Send External Object](/refguide/send-external-object/) activity.

{{% alert color="info" %}}
A Mendix commit does not always behave like a database commit. See [How Commits Work](#how-commits-work), below, for more information.
A Mendix commit does not always behave like a database COMMIT. See [How Commits Work](#how-commits-work), below, for more information.
{{% /alert %}}

## Properties
Expand Down Expand Up @@ -103,21 +103,53 @@ When inside a [nanoflow](/refguide/nanoflows/), the object is refreshed across t

## How Commits Work{#how-commits-work}

In understanding commits, it is important to remember that each persistable object has two states:

1. The state in the database where the values are shared with every other user of the app. This is the state you get when you retrieve an object which is not already in the app's memory.
2. The state in memory where values changed by the app can be seen.

Non-persistable entities behave like the in-memory version of a persistable object.

### Committing Objects

When you commit an object, the current value is saved. This means that you cannot roll back to the previous values of the object using the rollback object activity of a microflow.
When you commit an object which is in memory, all changes to the database values are saved. Once it is committed, you cannot roll back to the previous values of the object using the **Rollback object** activity of a microflow.
Copy link
Copy Markdown
Contributor

@lvanengelen-mx lvanengelen-mx Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all changes to the database values are saved

Do you mean all changes form the in-memory object are saved to the database? Or after the in-memory changes are saved to the database, the database values and in-memory object are in sync? The latter is not necessarily true if some other changes were committed earlier by some other user.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like:

When you commit an object which is in memory, its changes are saved to the database. The object is now unchanged and a roll back will have no effect.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest:

Suggested change
When you commit an object which is in memory, all changes to the database values are saved. Once it is committed, you cannot roll back to the previous values of the object using the **Rollback object** activity of a microflow.
When you commit an object which is in memory, changes to the values are saved in the database. Once it is committed, you cannot roll back to the previous values of the object using the **Rollback object** activity of a microflow.

But I want to specifically talk about Rollback object as this is different from the rollback which occurs with an error.


However, a Mendix commit is not the same as a database commit. For an object of a persistable entity, the saved value is not committed to the database until the microflow and any microflows from which it is called, complete. This means that errors in a microflow can initiate a rollback. If a microflow activity errors and has **Error handling** set to **Rollback** or **Custom with rollback**, the value of the object is rolled back to the value it had at the start of the microflow. See [Error Handling in Microflows](/refguide/error-handling-in-microflows/) for more information.
However, a Mendix commit is not the same as a database (SQL) COMMIT. When you use a **Commit object(s)** activity, Mendix actually performs an INSERT or UPDATE on the database. For an object of a persistable entity, the database COMMIT is not performed until the microflow and any microflows from which it is called, complete. This means that, although a retrieve from the database by the end-user's app will see the updated version of the object, the updated object will not be seen globally by other end-users until the microflows end.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a contradiction between this statement and Line 210 of error-handling-in-microflows (which I pulled in from the Mx8 documentation as people said it was useful). In what circumstances does the current end-user continue to see their changes?

If they have uncommitted changes, are these stored in the client and still available if they start a transaction and retrieve the object? Or are they lost if they aren't committed?

This statement implies that the changes continue to be visible to the user even outside the microflow (e.g. if you retrieve into a data container) whereas line 210 of error-handling-in-microflows says the changed data is only visible within the microflow.

I guess this one is more accurate otherwise a Change Object with Commit: No and Refresh in Client: Yes wouldn't work?

Can you confirm?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That line 210 says:

To ensure that every end-user or process can only see persisted data, data changed in a microflow is only available within that microflow. None of the changes made inside the microflow will be available outside the microflow, not even to the end-user that initiated the microflow. The information will only be available to all end-users of the application once the microflow has successfully completed all the activities.

I do not fully understand what this is meant to say. Changes made by the user in the client are (ephemerally) stored there and applied on in-memory objects when calling a microflow. So the end-user has access to the changes, because they are in the browser.

In what circumstances does the current end-user continue to see their changes?

As long as they do not refresh the page and the changes are not committed, these are stored in the client and passed to the runtime when necessary, where they become in-memory objects. When the microflow re-retrieves such an object from the database, this is another copy in memory with the same object id. By itself, this does not interfere with the changes in the client.

However, if the Refresh in Client setting is used on the object retrieved from the database, the runtime will tell the client in the response that it should update its state cache with the retrieved object for that id. This will remove the original change.

Returning the retrieved object as the microflow return value keeps the change.

To be honest, I was not 100% sure about the behavior in these 3 scenarios, so I reproduced them in a test project.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the investigation. I think there is too much to add to the documentation here, but I have tried to clarify line 210 of error-handling-in-microflows.md in this suggestion: https://github.com/mendix/docs/pull/10899/changes#r3074354106


Mendix mimics this behavior for non-persistable entities. Committing a non-persistable entity means that you cannot use a rollback object activity to go back to the previous values, although the rollback error handling in a microflow rolls back to the original values.
Another consequence of this distinction is that, in contrast to an explicit **Rollback object** call, which rolls back to the last Mendix commit, errors in a microflow can initiate a database rollback. If a microflow activity errors and has **Error handling** set to **Rollback** or **Custom with rollback**, the value of the object in the database is rolled back to the value it had at the last savepoint. See [Error Handling in Microflows](/refguide/error-handling-in-microflows/) for more information.
Copy link
Copy Markdown
Contributor

@lvanengelen-mx lvanengelen-mx Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... the value of the object in the database is rolled back to the value it had at the last savepoint

Explicitly mention that the in-memory changes are kept?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Another consequence of this distinction is that, in contrast to an explicit **Rollback object** call, which rolls back to the last Mendix commit, errors in a microflow can initiate a database rollback. If a microflow activity errors and has **Error handling** set to **Rollback** or **Custom with rollback**, the value of the object in the database is rolled back to the value it had at the last savepoint. See [Error Handling in Microflows](/refguide/error-handling-in-microflows/) for more information.
Another consequence of this distinction is that, in contrast to an explicit **Rollback object** call, which rolls back to the last Mendix commit, errors in a microflow can initiate a database rollback. If a microflow activity errors and has **Error handling** set to **Rollback** or **Custom with rollback**, the value of the object in the database is rolled back to the value it had at the last savepoint. The object in memory will, however, keep any changes to the values. See [Error Handling in Microflows](/refguide/error-handling-in-microflows/) for more information.


{{% alert color="warning" %}}
Deleting an object and then committing it can have different outcomes depending on whether the object has already been committed or not. If the object has already been committed, the delete will remove the object from the database, and the subsequent commit will have no effect. If the object is new (that is, it has not been committed before), the delete will do nothing, but the commit will store the object in the database. Therefore, this sequence of actions (a delete followed by a commit) may lead to unexpected results if the object has not been committed before.
{{% /alert %}}
#### What Gets Committed

When you work on an object in memory, Mendix records whether the object has been changed. When you perform a **Commit object(s)** activity, changes to the current values are written to the database and Mendix marks the object as unchanged in memory. This has a couple of consequences that you might not expect:

* If you commit an object which is then rolled back due to an error, committing the object again will not write the latest version to the database. You can understand this as the following sequence (see [Error Handling in Microflows](/refguide/error-handling-in-microflows/) for a more detailed discussion of how rollbacks work during error handling):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you commit an object which is then rolled back due to an error

Should we say instead that not the object is rolled back but the transaction is rolled back to the last savepoint?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea:

Suggested change
* If you commit an object which is then rolled back due to an error, committing the object again will not write the latest version to the database. You can understand this as the following sequence (see [Error Handling in Microflows](/refguide/error-handling-in-microflows/) for a more detailed discussion of how rollbacks work during error handling):
* If you commit an object and the transaction is then rolled back due to an error, committing the object again will not write the latest version to the database. You can understand this as the following sequence (see [Error Handling in Microflows](/refguide/error-handling-in-microflows/) for a more detailed discussion of how rollbacks work during error handling):


1. Your microflow starts and creates a savepoint.
1. You change your object in memory – it is marked as changed.
1. You perform a **Commit object(s)** activity which sends the changes to the database – the object in memory is marked as unchanged.
1. An error occurs after the **Commit object(s)** has successfully sent changes to the database – the microflow ends and data in the database is rolled back to the savepoint.
Copy link
Copy Markdown
Contributor

@lvanengelen-mx lvanengelen-mx Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make it more explicit that the error occurs in another action after the commit?

Our implementation of commit could be seen as Prologue > Database Commit > Epilogue Any error in Epilogue should restore the object to its original state, as that is the contract of the Commit action. So this scenario is really about errors in the activity after the commit.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll make it more explicit:

Suggested change
1. An error occurs after the **Commit object(s)** has successfully sent changes to the database – the microflow ends and data in the database is rolled back to the savepoint.
1. An error occurs in an activity after the **Commit object(s)** activity has successfully sent changes to the database – the microflow ends and data in the database is rolled back to the savepoint.

1. You perform a **Commit object(s)** on the object again, but the changes are not written to the database because:

* The object in memory still has your changes but it was marked as unchanged after your previous commit
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would avoid 'changes' here, as that implies that it is still in a changed state. Maybe 'committed values' is better?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about:

Suggested change
* The object in memory still has your changes but it was marked as unchanged after your previous commit
* The object in memory still has the updated values but it was marked as unchanged after your previous commit

* The **Commit object(s)** activity does not see the changed marker and so does not recognize that your object in memory has changes which need to be written.

If you want to keep the changes in the version which is in memory, you will have to work around this behavior by creating a new object which contains the changes.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I doubt that creating a new object is correct in general: you probably want it to be the same (i.e. with same object id) object. What would work is update any attribute value (even to its current value). That will mark the in-memory object as changed for the database. Not sure if we want to recommend that to users though...

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about:

Suggested change
If you want to keep the changes in the version which is in memory, you will have to work around this behavior by creating a new object which contains the changes.
If you want to keep the changes in the version which is in memory, you will have to work around this behavior by modifying the object again.

Is this vague enough? I feel like having said that the developer still has the modified version we need to suggest a solution that doesn't involve throwing the changes away and having to do the whole process (which may having involved end-user input) all over again.


* Deleting an object and then committing it has different outcomes depending on whether the object has already been committed or not:

* If the object has already been committed, the delete will remove the object from the database, and the subsequent commit will have no effect.
* If the object in memory is new (that is, it has not been committed before you delete it), the delete will do nothing. However, the subsequent commit will write the object to the database. Therefore, this sequence of actions (a delete followed by a commit) may lead to unexpected results if the object has not been committed before.

#### Committing Non-Persistable Entities

Mendix mimics this behavior for non-persistable entities. This means that:

* Performing a commit on a non-persistable entity means that you cannot use a **Rollback object** activity to go back to the previous values
* If an error occurs in a microflow, and you have error handling which does a rollback, the values roll back to the state a the previous savepoint.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the values roll back to the state a the previous savepoint.

The database values roll back to the state of the previous savepoint. But as non-persistable entities are not stored in the database, this does not matter for non-persistable entities.

Database rollback and object rollback are unrelated concepts. In-memory objects do not roll back on failure.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So is there no difference for Non-persistable entities between custom with rollback and custom without rollback. They will both behave as custom without rollback? Perhaps I could say that.

Suggested change
* If an error occurs in a microflow, and you have error handling which does a rollback, the values roll back to the state a the previous savepoint.
* If an error occurs in a microflow, and you have custom error handling, it will always act as a custom without rollback as persistable entities do not have a separate state in the database.


### Autocommit and Associated Objects {#autocommit-and-associated-objects}

When an object is committed through a default **Save** button, a commit activity, or web services, it always triggers the commit events. The platform also evaluates all associated objects. To guarantee data consistency, the platform may also autocommit associated objects.
When an object in memory is committed through a default **Save** button, a commit activity, or web services, it always triggers the commit events. The platform also evaluates all associated objects. To guarantee data consistency, the platform may also autocommit associated objects.
Copy link
Copy Markdown
Contributor

@lvanengelen-mx lvanengelen-mx Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it always triggers the commit event

Maybe make it explicit that this also holds when the object is not marked as changed (and therefore no actual database save will take place)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this, although true, is too much detail. I think "it always" is enough?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The platform also evaluates all associated objects.

What does this mean?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question - I don't actually know what it does but it has some sort of consistency check on all the associated objects. Not sure what else to say here.


An autocommit is an automatic commit from the platform, which is done to keep the domain model in sync. If your application ends up having autocommitted objects, then you will have a modeling error. Since an association is also a member of an object, the association is stored in the database as well. This means that if you create an order line inside an order and the order line is the parent of the association, when you commit the order line, the order is autocommitted.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,19 @@ This event can only be used in **Microflows**.

## Introduction

An error event defines where a microflow will stop and throw an error that occurred earlier. If you call a microflow, you may want to know whether any errors occurred within the microflow or not. This event throws the error again, so the caller of the microflow can catch them. When you use this event, all database actions within the current transaction will be rolled back (for more information, see [Error Handling in Microflows](/refguide/error-handling-in-microflows/)).
An error event defines where a microflow will stop and throw a new error based on the error that occurred earlier. If you call a microflow, you may want to know whether any errors occurred within the microflow or not.

When you use this event, it creates a new error with the same information as the original error. Because this is a new error, even if the error that occurred earlier was caught **without rollback**, all database actions within the current transaction will be rolled back (for more information, see [Error Handling in Microflows](/refguide/error-handling-in-microflows/)).
Copy link
Copy Markdown
Contributor

@lvanengelen-mx lvanengelen-mx Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all database actions within the current transaction will be rolled back

Do you mean 'since the last savepoint' (considering transaction is only on the outer level)? Or don't we make that distinction here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point - we are trying to avoid using "transaction". Would it be best to say "all database actions within the microflow?". I don't want to start talking about savepoints as we are only talking about how we exit the microflow here.

Should I say

Suggested change
When you use this event, it creates a new error with the same information as the original error. Because this is a new error, even if the error that occurred earlier was caught **without rollback**, all database actions within the current transaction will be rolled back (for more information, see [Error Handling in Microflows](/refguide/error-handling-in-microflows/)).
When you use this event, it creates a new error with the same information as the original error. Because this is a new error, even if the error that occurred earlier was caught **without rollback**, all database actions within the current microflow will be rolled back (for more information, see [Error Handling in Microflows](/refguide/error-handling-in-microflows/)).


{{% alert color="warning" %}}
You can only use an error event if an error is in scope: Studio Pro does not accept it if you connect the normal execution flow to an error event, because there would not be an error to pass back to the caller.
You can only use an error event if an error is in scope: Studio Pro does not allow you to connect the normal execution flow to an error event, because there would not be an error to pass back to the caller.
{{% /alert %}}

In this example, an error occurs while committing an object to the database. It is caught, and the flow continues to the error event where the error is passed back to the caller of the microflow. So you can implement your error handling on multiple levels.
## Example of Error Event

In the example below, an error flow is defined when performing a Mendix commit. Any error is caught, and the flow continues to the error event where the error is passed back to the caller of the microflow. This allows you to implement your error handling on multiple levels.

{{< figure src="/attachments/refguide/modeling/application-logic/microflows-and-nanoflows/events/error-event/error-event.png" class="no-border" >}}
{{< figure src="/attachments/refguide/modeling/application-logic/microflows-and-nanoflows/events/error-event/error-event.png" class="no-border" alt="A microflow with a parameter of 'MyEntity'. It has a single action committing 'MyEntity' which has an error flow ending in an error event and the normal flow ending in an end event" >}}

{{% alert color="info" %}}
When adding an error event, you need to add an [error handler](/refguide/error-handling-in-microflows/#errorhandlers) for an activity before the error event. Link an error event and an activity which has an error handlers set on it with a [sequence flow](/refguide/sequence-flow/) and select **Set as error handler** for the sequence flow.
Expand Down
Loading