Problems with editing beans in a BeanItemContainer

I have been using BeanItemContainer for some time but now I’m running into more and more problems and wanted to ask the community for some insights. A lot of the time I’m using JPA entities but I don’t want to use JPAContainer because I want a service layer between frontend and data access. Most problems are independent of the used persistence anyway.

I have multiple use cases for displaying and editing beans contained in containers. The simplest case is just having a flat list of beans that can be edited, e.g., in a dialog. If I use the generated ID for equals(), all works fine. If I use business values for equals() as it is recommended, I have problems when editing beans: Since the beans are part of data structures that work with hashes (e.g. keys in a Map in BeanItemContainer), their hashcode is not allowed to change. So I’m forced to reload the whole table only because I change a small thing. This is annoying because it takes time and causes the table to forget its selection and scroll to the beginning again which makes not for a very good user experience. I tried replacing only the bean in question but this increased complexity and selection is still lost. Even if I use the ID, I still need to replace the bean after I persisted it with JPA because if I don’t use the instance returned by persist(), strange errors happen later if there are relationships to other entities.

The more complex case is editing a collection of beans that are a property of another bean. I always want the user to be able to modify the nested list of beans but then change his or her mind and cancel everything. Also the containing bean does not necessarily have to exist yet. The list could be modified as part of the outer beans creation process. For the contained beans I cannot use the ID for equals() anymore because then I cannot have more than one non-persisted bean in the list (because the ID is initially null). Using business values makes more sense but then I have the same problem as mentioned above.

I don’t know, it always sounds so simple but in practice a lot of code is required for all the resulting special cases and the result is still pretty brittle.

Maybe something hasn’t quite clicked with me yet. Do you have any suggestions, best practices or patterns that simplify that?

Hello,
I faced the same problem and finished with not elegant, but working solution: I implemented my descendant of
BeanItemContainer
, where
itemIdToItem
field is
IdentityHashMap
insted of
HashMap
as in original
AbstractBeanItemContainer.
As a result I needed to copy all the methods from
BeanItemContaner
that use this field to my class.
It is not elegant, but works well.

You could use an application generated ID instead. For example a global long id generator for the entire database, a per table ID generator or a UUID generator.

I usually use the generated database ID for all but problematic beans.

Reloading entities, in a table for example, after adding or editing a bean is usually forced if the table is filtered or sorted. However, reloading only a visible page should not cause performance penalties.

Keeping the size of a BeanItemContainer as short as needed to show the visible rows in a table and refilling it with a business method on page changes is the best option that I found to show tabular data with thousand or millions of records with a good performance.

Database related indexed containers will fail due the
Indexed.indexOfId()
method that doesn’t have a portable relational database query. (Some implmentations use the index as itemId or keep a hash with all loaded itemIds by index).

Maybe you could find useful my
JDAL Library
that focuses on this topic.

Thanks for your answers so far.

I thought about that, too. I think it would be a good feature for AbstractBeanContainer to be able to provide a custom mapping. It currently solely relies on equals()/hashCode() of the item IDs.
Your solution doesn’t happen to be hosted on GitHub or Vaadin’s addon directory, does it? :slight_smile:

I thought about generating IDs as well. I used to wonder why you’d ever need to create IDs in the application when the database does such a fine job at it; now I know.

I’m not sure I understand. It’s true that I need to sort or filter a container after editing an item (another questionable design decision imho) but this should not require recreationg of the content. It can be done in memory. What I bemoan is the fact that I cannot easily edit the items in place for reasons mentioned in my first post but have to empty the container and go fetch the data from the database again.

Thanks, I’ll take a look some time. :slight_smile:

No, it’s not, because it is not really legitimate solution. But I can share those 2 classes. Use them at your own risk ;-).

I’ts just to point that refreshing current view state after modification should not be a issue.

If you hold a partial view of a database table (ie, a page) in a component and then change the database table adding or modifying a entity, now the component hold stale data. There is no way to refresh the component in memory unless you hold the entire table. How to know which entities should enter/go in the current view? . So IMHO, the best option is refreshing the current page from database.

In the other hand, if you hold a view of dependents beans of a entity in a component and add or modify a dependents bean, the view state is fine as you still don’t change the database (and usually the component holds all dependents beans). In this case I choose between default object identity if acceptable, or an application generated one, usually a unique long generator for the entire database.

An UUID generator works too, but I feel that is too expensive and ugly for manual inspecting or querying. A good business key should work fine, but I’m not an enthusiast of them (although JPA vendors recommend them) and not always is there.

Ok. I try to leverage data binding for that. If I want to edit a bean from a table with a BeanItemContainer, I just hand the item to the dialog and edit that by binding the properties to fields. The container gets notified of changes and updates immediately. Calling Table#sort() guarantees that the table stays sorted. This also regenerates all generated columns. Usually I’d be done then. But after passing an entity bean to persist() or merge() I sometimes get a new instance back which should be used for the next persist(). But this requires a lot of special handling. It is usually just easier to regenerate the whole table again.

Yep, I agree. It certainly would solve the problem but then I lose the independence between model and view. If I don’t absolutely have to, I wouldn’t really want to compromise the data model just because the view is incapable of handling certain things.

Hi,

Could you extract a minimalistic example of the case to e.g. github? Would be easier to suggest solutions if we could really see the code we are working with.

BTW. About implementing equals/hashCode in JPA entities. This is bit controversy, but definitely not implement them based on “business values”. It is not just with Vaadin where you’ll end up having problems. Identifier is one simple option but even that might have issue with yet to be persisted entities.

cheers,
matti