Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uniform handling of JPA and DTO entities in standard list/detail views #2819

Conversation

knstvk
Copy link
Contributor

@knstvk knstvk commented Jan 31, 2024

See #2788 for the problem description.

Added methods

  • EntityStates.setNew(Object entity, boolean isNew) - manages the "New" state of the entity instance.
  • RemoveAction.setDelegate(), RemoveOperation.RemoveBuilder.withRemoveDelegate() - delegate to be invoked instead of DataManager to remove the entities from a storage
  • StandardDetailView.setReloadEdited(boolean) - whether the edited entity should be reloaded before setting to the data container. True by default.

Removed methods

  • Protected StandardDetailView.entityCanBeLoaded()
  • Protected DetailViewNavigationProcessor.isNeedToSetEntityToEdit()
  • Protected DetailViewNavigationProcessor.getEntityToEdit()

Behavior changes

The framework now doesn't make any difference between JPA and DTO entities when navigating to a detail view: it passes the entity ID in the route parameter. The detail view for DTO entity is supposed to get this ID and load the entity instance from some data storage using the load delegate. If the new constant is passed instead of ID, the view creates a new instance.

If the whole entity instance is passed instead of ID (e.g. when opening in dialog window), EntityStates.isNew() is used to distinguish between Edit and Create mode. Consequently, it's important to set the entity in the not-new state after loading it from a storage. For a DTO entity it can be done using the new EntityStates.setNew() method, for JPA entity it's done by the standard JPA data store implementation.

If the edited entity should not be reloaded from the data storage before setting to the data container, call setReloadEdited(false) in the detail view constructor or InitEvent handler. This is the case for DTO entities existing purely in memory and not mapped directly to external data, like Security or JMX Console model entities.

Recommendations

Opening DTO entity detail view

Previously, the framework automatically adjusted the process of opening detail views for DTO entities. In particular, when navigating, it didn't provide the entity ID in route parameters and instead passed the entity instance in AfterViewNavigationEvent handler.

If you have used this standard approach for navigation and want to keep it, you should replicate the old behavior in create/edit actions of the list view as in the following example for the Phone DTO entity:

@Autowired  
private ViewNavigators viewNavigators;
@ViewComponent  
private DataGrid<Phone> phonesDataGrid;

@Subscribe("phonesDataGrid.create")  
public void onPhonesDataGridCreate(final ActionPerformedEvent event) {  
    viewNavigators.detailView(phonesDataGrid)  
            .withViewClass(PhoneDetailView.class)  
            .withRouteParameters(RouteParameters.empty())  
            .withAfterNavigationHandler(afterViewNavigationEvent -> {  
                Phone phone = metadata.create(Phone.class);  
                afterViewNavigationEvent.getView().setEntityToEdit(phone);  
            })  
            .navigate();  
}  
  
@Subscribe("phonesDataGrid.edit")  
public void onPhonesDataGridEdit(final ActionPerformedEvent event) {  
    viewNavigators.detailView(phonesDataGrid)  
            .withViewClass(PhoneDetailView.class)  
            .withRouteParameters(RouteParameters.empty())  
            .withAfterNavigationHandler(afterViewNavigationEvent ->  
                    afterViewNavigationEvent.getView()  
                            .setEntityToEdit(Objects.requireNonNull(phonesDataGrid.getSingleSelectedItem())))  
            .navigate();  
}

As you can see, the action handler methods set the empty route parameters and pass the entity in AfterViewNavigationEvent handler.

Opening detail view in dialog window should work as before without changes in list view actions.

Both for the navigation and dialog mode, call setReloadEdited(false) in the detail view:

public PhoneDetailView() {  
    setReloadEdited(false);  
}

Setting non-new state for loaded DTO entities

To make sure the framework correctly distinguish new instances from already existing in a storage, call EntityStates.setNew(entity, false) for entities loaded from external storage.

Assigning ID to new DTO entities

If the new entity ID is assigned by the storage, set the ID to the original instance too to let the framework match the saved instance with the original one. For example:

public Task saveTask(Task task) {
    String url = task.getId() != null ? TASKS_BASE_URL + "/"  + task.getId() : TASKS_BASE_URL;
    ResponseEntity<Task> response = restTemplate.postForEntity(url, task, Task.class);
    Task savedTask = Objects.requireNonNull(response.getBody());
    if (task.getId() == null) {
        task.setId(savedTask.getId());
    }
    entityStates.setNew(savedTask, false);
    return savedTask;
}

@knstvk knstvk linked an issue Jan 31, 2024 that may be closed by this pull request
@knstvk knstvk marked this pull request as ready for review February 1, 2024 08:38
@knstvk knstvk self-assigned this Feb 4, 2024
@knstvk knstvk merged commit 0e79416 into master Feb 5, 2024
@knstvk knstvk deleted the feature/2788-Uniform-handling-of-JPA-and-DTO-entities-in-standard-list-detail-views branch February 5, 2024 05:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Uniform handling of JPA and DTO entities in standard list/detail views
3 participants