Maybe I am in the wrong challenge.
But I love your maker of the month challenge to challenge us every month to think about problems we may not experience everyday, so thank you for that.
I am a bit of a RADically free thinker, so I come again with an alternative answer that not necessarily makes me a prize winner.
While Non Persistent objects help in applications to implement a better capacity to handle a larger workload (as the database only has to work when an action of filling in a form completes for example) I would like to challenge Mendix this month.
But what I don’t like about Non Persistent objects is that they clutter my Domain Model. Duplicating my Persistent entities to Non Persistent is not the most elegant way of working I can imagine.
Early in my carreer I got exposed to Delphi RAD, around the time of 1994. And I am still not finished with it.
What I like about Delphi is that for Forms (compares well with Pages in Mendix), you have in addition to Properties also a tab called Events:
If in Mendix it was possible for Widgets and Pages to also have an option to configure events, we could come to a different solution that would be “Less Code”
For example, I would love to have an option to run a microflow/nanoflow before the Page shows, which would allow to do the necesarry preparation actions, like and if you wish, create non persistent objects first.
If in addition there would be a possibility to have an OnSave or OnClose event that could run another microflow to handle the actions on submission – this can of course also be implemented by having your Save button not execute the default action but run a microflow, you could easily transfer Non-Persistent objects into persistent objects and finish the job.
And if I may take even more freedom to think what I would like, I would like Mendix to make it configurable at page level which Entity/Object you want to create with your page, have it automatically make the Persistent object accessible without creating it in the database to allow via microflows to do your prep work, and have it accessible in the OnClose or OnSave event to allow finishing the job. If you would not need to create a Persistent object first before you can show an _New form, we could easily answer/solve this months quest.
Also not an answer Mendix is looking for because in a lot of cases I start with non-persistent objects for some new functionality but end up making some persistent because I can not reach my goals otherwise. Indeed as Johan stated it would be so nice if a persistent entity could inherit from a non persistent so that the persistent object always had some non persistent attributes as well that you can use for conditional visibility etc. And indeed Rob also has some good suggestions on how to make non-persistent entities even more valuable.
I've been using non-persistent entities a lot in the solutions I created and/or maintained. I think adding non-persistent entities to the platform was one of the biggest improvements Mendix made to the platform over the years.
With regard to this challenge, I'm not sure this is an either/or. For simple user interactions, it can be sufficient to rely on the standard user interactions of viewing, editing and deleting which you're able to design and implement with persistent objects. In the same application, more complex user interactions can require the use of non-persistent objects to properly support the user interactions.
Non-persistent entities in the user interface allow for user task specific handling of data. Using persistent objects, you're often faced with challenges with regard to storing the results of user actions. User actions that are part of a chain of user actions to store complex data, you have to store in most cases before the complete sequence has been finished. Although this does not lead to database inconsistency, the more complex data structure can be inconsistent for the time the process has not been completed. Using persistent objects, one constantly has to keep this in mind and make sure this inconsistency is corrected, if the process was not finished properly for whatever reason.
Non-persistent entities can be geared to the complex of user actions, rather than the data structure. The data input of the user can be captured in non-persistent objects during the actions. The data can be validated after each action but does not need to be stored in persistent objects until all actions are completed. Only when everything is done, the data can be stored in the persistent objects, not allowing for any inconsistency.
Another advantage of non-persistent objects is the level of control it gives to Mendix Consultants to design proper user interactions. As not all data used in the process is stored in the database, it is possible to add process-specific attributes to the non-persistent objects to manage the user interaction sequence. An example would be, showing information/data based on the process step the user is in.
Presenting data to the user, one is not always able to show information from parent entities up the hierarchy. A datagrid, based on a microflow data source, cannot display information from entities that are more than one up in the hierarchy. Using non-persistent entities, this information can be retrieved and temporarily stored in non-persistent objects to show to the user.
Implementation the change
Some main steps in implementing a change from persistent to non-persistent objects used in a current (set of) page(s) supporting a complex set of user interactions, are the following:
* Redesign the user interactions to really fit the desired goal of providing the user with a clear and easy to understand process of manipulating the data.
* Determine the data structure required to support the process and implement that with non-persistent objects. The main objects can probably be copied to non-persistent objects, postfixed with NP, to distinguish them from the persistent ones. After copying, add the extra attributes required for the user interactions and remove the ones you don't need in the process.
* Create the pages, the microflows to fill the non-persistent data structure used in the pages, the validations of the non-persistent data and the custom commit of the result of the process to persistent objects.
I tried to keep my answer brief and clear 😉
Non-persistent entities may be very valuable in a lot of cases, but one should always keep the downsides in mind.
If you only need one non-persistent object on your page, for example to determine which functionalities (buttons/view) are applicable to the specific item you want to show, you definitely can create a non-persistent object, for example as page parameter. Determining the functionalities you want to show can be done using custom logic in a microflow before opening the page and stored attributes of that object, preferable booleans or enumerations to make easy conditional visibilities.
If you want to customize the view of a list by creating a list of non-persistent objects, you should be more careful, but there are some delighters:
Downsides of showing a list of non-persistent entities, which have data copied from persistent entities:
As feature request: I would love to see of non-persistent attributes "attached" to a persistent entity. So they can be used in microflows, but won't be stored in the database. This fulfills the need of helper attributes most of the time.
I use non-persistable entities a lot. Below are a few examples based on a real application.
According to the documentation “Non-persistable entities are stored in the runtime memory and never get committed to the database”.
I have been using them in following cases
Avoid duplication of visibility and editable conditions
Example: you have a page with different widgets (fields, buttons). Depending on the situation (like status of the request, who is the user, what time of the day, …) we need to hide/show the widget or make it editable or read only.
Customer data may only be modified under certain conditions. Suppose the condition is complex and may only be calculated by a microflow. Even in case of a simple condition you must stick to the DRY (do not repeat yourself) principle: the condition must exist in a single location.
Further assume that the fields cannot be placed in a single container.
The normal page design looks like
I introduce a non persistable entity CustomerUI that contains properties for various visibily conditions.
The new domain model becomes
The page design must be based on CustomerUI
The last part is the creation of a microflow that creates a CustomerUI object each time a Customer page is opened. This happens when a new customer is created or when an existing customer is opened.
The microflow Sub_CustomerUI_New will do the job.
This microflow is called when editing a customer from a grid. Change the default on click action from “open page” to “call a microflow Act_Customer_Edit”
The microflow Act_Customer_Edit is straightforward
The button New Customer is very similar. It calls the microflow Act_Customer_New. This microflow creates a Customer object, then a linked CustomerUI object and opens the page.
Passing parameters to and from microflows
A good Mendix design will be based on many microflows and sub-microflows. When calling a submicroflow parameters must be passed. These parameters do not always correspond to your domain entities.
You could group parameters into an object. You need a corresponding entity in the domain model. There is no reason to persist the entity.
Limitations of non persistable entities
Non persistable entities have some limitations. For example
A a workaround you could define CustomerUI as persistable but never commit the object. You do not have the error message and still everything is kept in memory. There is just a dummy table in the database; but it will have no records.
@Lars Theunissen, what happened to the December Maker of the Month Challenge?