I will write about few details connected with hibernate which are not commonly known.
- *Any
- Lazy loading - not working in all cases as expected
- Eager loading - list collections
- @MapsId
- FetchMode and graphs
- Default constructor
- Final attributes
Ad 1.
It is rarely to find @Any or @ManyToAny relation in code. However it is useful when it is need to create relation with many class's types. Table referring to many types should have additional column which defines a related type.
1 2 3 4 5 6 | @AnyMetaDef(name= "Vehicle", metaType = "string", idType = "int", metaValues = { @MetaValue(value = "C", targetEntity = Car.class), @MetaValue(value = "M", targetEntity = Motor.class) } ) |
In this case in additional column are archived C and M - value of meta. Vehicle which is a interface for this two classes Car and Motor is used as a type in related entity. Principle of operation is similar to hardly typed relations.
Ad 2.
Lazy loading for relations @*ToOne not always works as it could be expected. Everything is connected with assumption that it is needed to know if relation with current entity is empty or not. When the key of relation is situated in coupled table, it is required to call additional query to check if that relation exists or not. If there is a relation hibernate creates proxy if not, it leaves null value. If we assume that entity has always related object it is possible to set attribute optional to false. In this case hibernate always creates proxy.
Other solution for this problem is to change table for relation key or manipulate with LazyToOne annotation and doesn't create proxy, what is not required.
Lazy loading for relations @*ToOne not always works as it could be expected. Everything is connected with assumption that it is needed to know if relation with current entity is empty or not. When the key of relation is situated in coupled table, it is required to call additional query to check if that relation exists or not. If there is a relation hibernate creates proxy if not, it leaves null value. If we assume that entity has always related object it is possible to set attribute optional to false. In this case hibernate always creates proxy.
Other solution for this problem is to change table for relation key or manipulate with LazyToOne annotation and doesn't create proxy, what is not required.
Ad 3.
It is not common but sometimes I meet in entities that to keep collection some people use List. It is not recommended because some queries can receive multiplied instance of one row, especially it is common when it is used eager fetch mode.
In case when one entity has more then one eager list collection, we get javax.persistence.PersistenceException during start-up.
It is not common but sometimes I meet in entities that to keep collection some people use List. It is not recommended because some queries can receive multiplied instance of one row, especially it is common when it is used eager fetch mode.
In case when one entity has more then one eager list collection, we get javax.persistence.PersistenceException during start-up.
Ad 4.
@MapsId is an annotation which makes relation key of as primary key. It looks better in db, especially when entity has embedded key.
@MapsId is an annotation which makes relation key of as primary key. It looks better in db, especially when entity has embedded key.
Ad 5.
JPA 2.1 introduce new feature - entity graph. This feature allows to change featch mode in runtime. One what is required, it is needed to define some path of connections between entities and use this definition in Query as a hint. This feature was available before JPA 2.1 but it wasn't standardized, so each implementation resolved it in other way.
Bellow some example.
1 2 3 4 5 6 | @NamedEntityGraphs({ @NamedEntityGraph(name = "graph.Index.countrySymbols", attributeNodes = {@NamedAttributeNode(value = "country"), @NamedAttributeNode(value = "symbols")}), @NamedEntityGraph(name = "graph.Index.country", attributeNodes = {@NamedAttributeNode(value = "country")}) }) |
This part of code is added to class and then used by @Hint("graph.Index.countrySymbols") annotation.
You can find more [ref. 3]
Ad 6.
Hibernate requires default constructor (even private). Even using spring 4+ and Hibernate 5.2 I've got exception:
Caused by: org.hibernate.InstantiationException: No default constructor for entity: entity.Bill.
It is a little strange for me because problem with instance creation, which was common for cglib, was resolved in Spring 4+ so I expected it should involve jpa entities as well.
Ad 7.
Hibernate ignores final type of variable in entity, especially it is noticeable when entity has defined some collection, initialised by the way of declaration. Chosen in declaration HashSet is replaced by hibernate implementation PersistentSet.
Resources:
Hibernate ignores final type of variable in entity, especially it is noticeable when entity has defined some collection, initialised by the way of declaration. Chosen in declaration HashSet is replaced by hibernate implementation PersistentSet.
Resources:
- https://stackoverflow.com/questions/37282850/hibernate-org-hibernate-loader-multiplebagfetchexception-cannot-simultaneousl
- https://stackoverflow.com/questions/13334831/multiplebagfetchexception-thrown
- https://www.thoughts-on-java.org/jpa-21-entity-graph-part-1-named-entity/
- https://martinsdeveloperworld.wordpress.com/2014/07/02/using-namedentitygraph-to-load-jpa-entities-more-selectively-in-n1-scenarios/
- https://stackoverflow.com/questions/17987638/hibernate-one-to-one-lazy-loading-optional-false
- https://vladmihalcea.com/2016/07/26/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/