Link to home
Create AccountLog in
Avatar of Jack McKenzie
Jack McKenzie

asked on

How should we annotate Java entities to persist lists and then make lazy loading work?

In Java, I have a requirement to allow user-defined properties.

Example:
Database table: property

Table Row:
ID: 1
Label: Annual Salary

Database table: contact
ID: 1
Email: test@example.com
...

In addition to existing columns for contacts, users will define their own columns in Property Manager. Such column is "Annual Revenue" (number) for example.

So we need a table:
Database table: contact_properties
ID: 1
Contact_id: 1
Property_id 1

In this table we link user-defined properties to contacts

We however need more. We have 4 fixed (immutable) field types: Text, Number, Checkbox, Dropdown.
Every user-defined property should have a type, something like in MS Excel, but easier.

And finally, every user-defined property should belong to some group. Groups are user-defined too.

Database table: property_group

Row:
ID: 1
Label: Contact Information

ID: 2
Label: Company information

...

How should we annotate entities in Java to persist the above? Attached is all source code (mini project). See the entity package in module-properties. I have also prepared something quickly in the App.java (main) to test persistence.

The current exceptoin is:
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: uk.co.mybigdata.crm.module.properties.entity.Property.optionList, could not initialize proxy - no Session
      at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:582) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
      at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:201) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
      at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:561) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
      at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:132) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
      at org.hibernate.collection.internal.PersistentBag.toArray(PersistentBag.java:283) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
      at uk.co.mybigdata.crm.application.App.run(App.java:85) [classes/:na]
      at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:797) [spring-boot-2.0.2.RELEASE.jar:2.0.2.RELEASE]
      ... 5 common frames omitted
elements.zip
ASKER CERTIFIED SOLUTION
Avatar of girionis
girionis
Flag of Greece image

Link to home
membership
Create an account to see this answer
Signing up is free. No credit card required.
Create Account
Avatar of Jack McKenzie
Jack McKenzie

ASKER

Transactions are managed by the container, as you see in the code, so I have annotated App.java run() with @Transactional and it has helped!

The full answer comes from StackOverflow (the exact same stack trace - Hibernate attempts to lazy load from a bag, uses a temporary session if needed, then throws the exception because the session has been closed = same last 3 stack trace steps).

https://stackoverflow.com/questions/19304671/cannot-fetch-lazy-jpa

The solution is to eager load the collection, or annotate the method @Transactional, or make the session scope broader, possibly with a filter.