Hibernate execute OneToMany if condition satisfied - java

I was wondering if it exist a way to tell to Hibernate to execute the query behind a #OneToMany only if a condition is satisfied.
This could be a very simple example:
#Entity
public class MyEntity {
...
private Long id;
private boolean condition;
private List<AnotherEntity> anotherEntity;
#Id
#Column(name = "ID", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Basic
#Column(name = "CONDITION")
public Boolean getCondition() {
return isContentChanged;
}
public void setIsContentChanged(Boolean condition) {
this.condition = condition;
}
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "SECOND_ID")
**#Conditional(clause = "CONDITION = true")**
public List<AnotherEntity> getAnotherEntity() {
return anotherEntity;
}
public void setAnotherEntity(List<AnotherEntity> anotherEntity) {
this.anotherEntity = anotherEntity;
}
}
#Entity
public class AnotherEntity {
private id
private secondId
...
}
So what I would like is:
- if the condition in the annotation #Conditional is satisfied, Hibernate execute the query related to the #OneToMany annotation
- if the condition in the annotation #Conditional is not satisfied, Hibernate do nothing with the #OneToMany annotation
I do not know if that already exist somewhere in Hibernate. Otherwise could be a great new feature.

One way you may be able to solve this depending on the context of AnotherEntity would be to use a Hibernate Filter. I have used something similar in the past where we had a OneToMany of a specific entity type but only certain values were to be returned based on user access.
Other ways may include using a #Formula or #Where annotation.
All three of these options are available in the documentation for Hibernate 5.2, starting here.
Update:
What I am about to explain only applies to associations which are explicitly defined as LAZY fetch types. If you keep the default EAGER fetch type or explicitly set it to EAGER, the following does not apply.
Given that your association is using LAZY fetch types, you could bake the condition as a part of your data access layer queries at runtime. There isn't an annotation to this so it would be part of your code but it at least allows you to minimize the join at runtime.
For situations where your condition is true, you either specify that the collection should be loaded EAGER if using the deprecated Hibernate Criteria API or you'll want to use a JOIN/JOIN FETCH if using the JPA Criteria API. Note that JOIN will only allow you to apply predicates again the collection to filter the root entities; however JOIN FETCH will also populate the collection for you.
This won't allow you to filter the collection results but it at least provides you a means to eliminate the join while allowing the join to be part of the query at runtime based on some condition.
This is very analygous where a search form has 10 searchable fields; however you only apply the appropriate predicates to a base query if a given field has a value; however no predicate and perhaps no specific joins are added to the base query if a value is not provided to improve runtime query performance.

Related

JPA unidirectional #OneToOne relationship with shared primary key always trigger a secondary query even if fetchType is EAGER

I am building a blog system, and like to provide the upvote/downvote feature for the blog. Since the vote count number of blog should be persisted, i choose to use MySQL to act as the data store. And i use Spring JPA(Hibernate) to do the ORM job. Here's my data objects:
class Blog{
// ...
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne(optional = false, fetch = FetchType.EAGER)
#PrimaryKeyJoinColumn
private BlogVoteCounter voteCounter;
}
And the counter class:
#Entity
public class BlogVoteCounter extends ManuallyAssignIdEntitySuperClass<Long> {
#Id
private Long id;
private Integer value;
}
The reason why i separate the BlogVoteCounter from Blog is that i think the voteCount field will be modified by a totally different frequency comparing to other fields of Blog, since i want to use cache to cache the Blog, following this guide, i choose to separate them.
However, since the VoteCount field might be always needed when return the Blog object to the front end, and to avoid the n+1 problem, i declared the BlogVoteCounter field in Blog class with EAGER fetch type.
I've already seen this article. Thus according to my personal comprehension, i use unidirectional relationship and only declare OneToOne in the Blog side.
However, when i examine the query, it turns out that jpa will still trigger a secondary query to retrieve BlogVoteCounter from database without simply using a join when use findAll method on BlogRepository.
select
blogvoteco0_.id as id1_2_0_,
blogvoteco0_.value as value2_2_0_
from
blog_vote_counter blogvoteco0_
where
blogvoteco0_.id=?
So how should i config, to always make the BlogVoteCounter field in Blog be fetched eagerly.
The usage of ManuallyAssignIdEntitySuperClass is following the Spring JPA doc, since i manually assign id for BlogVoteCounter class.
#MappedSuperclass
public abstract class ManuallyAssignIdEntitySuperClass<ID> implements Persistable<ID> {
#Transient
private boolean isNew = true;
#Override
public boolean isNew() {
return isNew;
}
#PrePersist
#PostLoad
void markNotNew(){
this.isNew = false;
}
}
And the BlogRepository is derived from JpaRepository
public interface BlogRepository extends JpaRepository<Blog, Long>{
// ...
}
I trigger the query by using findAll method, but using findById or other conditional query seems no difference.
When to fetch vs How to fetch : fetchType defines when to fetch the association ( instantlyvs later when someone access) the association but not how to fetch the association(i.e second select vs join query). So from JPA Spec point of view, EAGER means dont wait until someone access that field to populate it but JPA provider is free to use JOIN or second select as long as they do it immediately.
Even though they are free to use join vs second select, still I thought they should have optimised for join in the case of EAGER. So interested in finding out the logical reasoning for not using the join
1. Query generated for repository.findById(blogId);
select
blog0_.id as id1_0_0_,
blog0_.vote_counter_id as vote_cou2_0_0_,
blogvoteco1_.id as id1_1_1_,
blogvoteco1_.value as value2_1_1_
from
blog blog0_
inner join
blog_vote_counter blogvoteco1_
on blog0_.vote_counter_id=blogvoteco1_.id
where
blog0_.id=?
2. Updated Mapping
public class Blog {
#Id
private Long id;
#ManyToOne(optional = false, cascade = ALL, fetch = FetchType.EAGER)
#PrimaryKeyJoinColumn
private BlogVoteCounter voteCounter;
public Blog() {
}
public Blog(Long id, BlogVoteCounter voteCounter) {
this.id = id;
this.voteCounter = voteCounter;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public BlogVoteCounter getVoteCounter() {
return voteCounter;
}
public void setVoteCounter(BlogVoteCounter voteCounter) {
this.voteCounter = voteCounter;
}
}
3. Issues with current Mapping
As per your mapping, it is impossible to create blog and votecounter as it causes a chicken and egg problem.
i.e
blog and votecounter need to share the same primary key
blog's primary key is generated by database.
so in order to get the primary key of blog and assign it to votecounter as well, you need to store blog first
but the #OneToOne relationship is not optional, so you cannot store blog first alone
4.Changes
Either need to make the relationship optional so blog can be stored first, get the id, assign to BlogVoteCounter and save the counter
Or Don't auto generate Id and manually assign the id so blog and votecounter can be saved at the same time.(I have gone for this option but you can do first option)
5.Notes
default repository.findAll was generating 2 queries so I overridden that method to generate one join query
public interface BlogRepository extends JpaRepository<Blog, Long> {
#Override
#Query("SELECT b from Blog b join fetch b.voteCounter ")
List<Blog> findAll();
}
select
blog0_.id as id1_0_0_,
blogvoteco1_.id as id1_1_1_,
blog0_.vote_counter_id as vote_cou2_0_0_,
blogvoteco1_.value as value2_1_1_
from
blog blog0_
inner join
blog_vote_counter blogvoteco1_
on blog0_.vote_counter_id=blogvoteco1_.id

Return ResultSet with intact joins in Hibernate / JPA

I have 2 entities: EntityA and EntityB. They are related with a One To Many relation.
public class EntityA {
#Identifier
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="ID", updatable = false, nullable = false)
private long id;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name="ENTITY_A_ID", referencedColumnName="ID", nullable=true)
private List<EntityB> entityBs;
/* GETTERS SETTERS ... */
}
public class EntityB {
#Identifier
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="ID", updatable = false, nullable = false)
private long id;
#Column(name="SOME_PROPERTY")
private String someProperty;
#ManyToOne
#JoinColumn(name="ENTITY_A_ID")
private EntityA entityA;
/* GETTERS SETTERS ... */
}
I have a query that joins EntityA with a LEFT JOIN to Entity B. And a 'ON' clause.
In normal SQL lingo this would be:
select * from EntityA eA left join EntityB eB
on (eA.ID = eB.ENTITY_A_ID and eB.SOME_PROPERTY = "blabla" )
where ...
So I'm having much needed information from my joined resultset. I only want records joined if they match certain properties. I need EntityA, allways, and an attached EntityB if EntityB matched the join clause.
The project is set up with Hibernate / JPA. I can't figure out how to retreive the information needed. At this moment I have:
public class EntityADAO {
public List<EntityA> findMethod() {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<EntityA> query = builder.createQuery(EntityA.class);
Root<EntityA> entityARoot = query.from(EntityA.class);
Join<EntityA, EntityB> entityBJoin = entityARoot.join("entityB", JoinType.INNER);
entityBJoin.on(new Predicate [] {builder.equal(entityBJoin.get("someProperty"), "fixed_val_for_now"});
/* where clause left out for readability */
TypedQuery<EntityA> q = entityManager.createQuery(query);
return q.getResultList();
}
}
So here I am.. Stuck with my List of EntityAs. whenever I call getEntityBs() on a EntityA, I'm getting all of them.. And this makes sense.. But How can I retrieve the joined set?
I'm stuck with JPA and Hibernate, as this choice is not made by me.
Thanks in advance!
What you need here is a custom projection or DTO. Filtering the entity collection might cause a delete because entities always reflect the current DBMS state and are synchronized at the end of the transaction.
You can write a JPQL query, just like the SQL one, that does what you want.
SELECT a.id, b.id
FROM EntityA a
LEFT JOIN EntityB b ON a.id = b.entityA.id AND b.someProperty = 'blabla'
But this won't help you with the materialization of the results into rich objects. If an Object[] i.e. the tuples are good enough for your use case, then use this kind of query and be done, but if you want to map to rich objects, I can recommend that you take a look at Blaze-Persistence Entity-Views.
Blaze-Persitence is a query builder on top of JPA which supports many of the advanced DBMS features on top of the JPA model. I created Entity Views on top of it to allow easy mapping between JPA models and custom interface defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure the way you like and map attributes(getters) via JPQL expressions to the entity model. Since the attribute name is used as default mapping, you mostly don't need explicit mappings as 80% of the use cases is to have DTOs that are a subset of the entity model.
A mapping for your model could look as simple as the following
#EntityView(EntityA.class)
public interface EntityAView {
long getId();
#Mapping("entityBs[someProperty = 'blabla']")
List<EntityBView> getEntityBs();
}
#EntityView(EntityB.class)
public interface EntityBView {
long getId();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
EntityAView dto = entityViewManager.find(entityManager, EntityAView.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

Lazy load doesn't work - I Only need the parent object, not all associations

How do get the object I want, without all of the child associations.
I have my class Site:
#Entity
#Table(name = "Sites")
public class Site {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Id_Site", unique = true, nullable = false)
private long Id_Site;
private String ...;
private boolean ...;
private long ...;
private Date ...;
private Date ...;
private String ...;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Sequence> sequences = new HashSet<>();
#ManyToOne
private ... ...;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<...> ... = new HashSet<>();
#ManyToOne
private ... ...;
public constructor...
public set..
public get..
}
I only need a Site object, without the Sequence Associations.
In my Sequence Table, I have:
#Entity
#Table(name = "Sequences")
public class Sequence {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Id_Sequence", unique = true, nullable = false)
private long Id_Sequence;
private Date ....;
private Date ....;
private String ....;
private String ....;
private String ....;
private int ....;
private int ....;
private double ....;
private double ....;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<TraceSequence> traceSequences = new HashSet<>();
#ManyToOne(cascade = CascadeType.ALL)
private Site site;
public constructor...
public set..
public get..
}
When I use FetchType.Lazy, and call my method:
#Override
public Site findSiteByName(String Name_Site) {
List<Site> sites = entityManager.createQuery("SELECT s FROM Site s").getResultList();
for (Site item : sites) {
if (item.getNom_Site().equals(Name_Site)) {
return item;
}
}
return null;
}
I get this error:
failed to lazily initialize a collection of role: xxx.xxx.xxx.xxx.xxx.site.Site.sequences, could not initialize proxy - no Session
When I use FetchType.EAGER, I get not only a Site object, but I also get all sequence objects, and all objects of other sequence associations. (I know it is the normal response.)
Could someone who knows why this attempt at lazy initialization doesn't work, please, tell me how to resolve this problem.
These lazy errors happens when the jpa tries to get the data after the session is closed.
But using eager will influence all the queries that include that entity.
Try to use a join fetch in the query instead of the eager.
Somewhere in your code you are calling Site.GetSequences(), maybe iterating in the view or in another part of your code. It doesn't look like the piece of code you gave are generating the exception.
I you try to use a collection that is not loaded to your entity, the code throws the exception you mentioned.
To solve this, identify where you are using the sequences and load them before you use by changing the fetch to EAGER or using the JOIN FETCH in your query.
Returning a hibernate managed entity (or a collection of hibernate managed entities) will most likely cause these sort of problems unless you are super cautious on what is being returned and what was populated by hibernate when session was available.
I would say create a DTO (or a collection of DTO) and populate its fields the way you like. There are many Entity to DTO conversion framework; my fav is ModelMapper.
I also tend to agree with other suggestions to play with FetchType but since DTOs are populated by us we know what we populated as opposed to entity-relationships which are populated by hibernate based on annotations.
If you need something in the DTO you simply ask the entity and since session would be available at that point of time you could populate any field that you think you would need on the UI.
I don't want to hijack this topic towards DTO and Entity but that's how I would do it.
This may be helpful too Avoid Jackson serialization on non fetched lazy objects
Error happen becouse you try execute getSequences(), but becouse of is lazy and session is alredy closed hibernate rais the error.
To avoid this error read read sequencese inside query method, "inside" session, like this:
public Site findSiteByName(String Name_Site) {
List sites = entityManager.createQuery("SELECT s FROM Sites").getResultList();
for (Site item : sites) {
if (item.getNom_Site().equals(Name_Site)) {
item.getSites();
return item;
}
}
return null;
}
This is a lazy loading, you read collenction just when you need it!
As stated by other SE members above, you are getting this error because session is already closed.
If you want to load a particular object then you can use Hibernate.initialize method. it will execute one additional query to fetch the data of related entity.
Therefore, it is as per need basis and will not be executed all times as compared to Eager loading
I'm working on a project that aims to solve common JPA problems when mapping entities to DTOs using ModelMapper. This issue has already been solved on the project. Project link: JPA Model Mapper
On this scenario I believe that we'd want to simply get null for all lazy load entities. For this question specifically, this could be done by using de JPA Model Mapper to map an entity to DTO.
I've already answered the same issue on this question: How to solve the LazyInitializationException when using JPA and Hibernate

Hibernate upgrade from 3 to 4: Criteria transaction ceases to work

I have recently upgraded Spring 2.5 to 3.2 and Hibernate 3 to 4.2.8 in a general upgrade of a web application. Most things are working now, but there is one Criteria transaction that is not working and has me puzzled. The new version returns no result (but no errors), while the old one retrieved properly the requested value.
The code is the same one in the old and new versions, and I have verified that the argument that reaches it is the same. Here is the Java code:
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(ViewingResource.class);
criteria.createCriteria("viewings","currentViewings");
criteria.add(Property.forName("currentViewings.id").eq(viewingId));
ViewingResource result = (ViewingResource)criteria.uniqueResult();
ViewingResource is my entity, which is defined as follows:
#Entity
#DiscriminatorValue("viewing")
public class ViewingResource extends AbstractInformationResource {
private static final long serialVersionUID = -4569093742552159052L;
#OneToOne(targetEntity = Attribute.class, fetch = FetchType.LAZY)
#JoinColumn
private Attribute primaryAttribute;
#OneToMany(targetEntity = Viewing.class, cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval=true)
#Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
#JoinTable(name = "informationresource_viewings")
#OrderBy("sort")
private Set<ResourceViewing> viewings;
public Set<ResourceViewing> getViewings() {
return viewings;
}
public Attribute getPrimaryAttribute() {
return primaryAttribute;
}
}
As for the abstract class it extends:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(
name = "type",
discriminatorType = DiscriminatorType.STRING
)
#Table(name = "informationresource")
abstract public class AbstractInformationResource extends PersistentEntity<String> {
private static final long serialVersionUID = 8709376067232042462L;
#Id #GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid")
private String id;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private int sort;
public String getId() {
return id;
}
public String getName() {
return name;
}
public int getSort() {
return sort;
}
}
And the original PersistentEntity is just an extension of Serializable with an id and no annotations.
I enabled Hibernate logs and found the problem may be in the way annotations work between in Hibernate 3 and 4, for the Hibernate generated SQL strings differ in this way:
Hibernate 3:
select
... (maps to all columns)
from
informationresource this_
inner join
informationresource_viewings viewings3_
on this_.id=viewings3_.informationresource_id
inner join
Viewing currentvie1_
on viewings3_.viewings_id=currentvie1_.id
where
this_.type in (
'viewing', 'directory'
)
and currentvie1_.id=?
Whereas in Hibernate 4, the generated SQL performs no joins:
select
... (maps to all columns, except type, attributeType and fieldName)
from
informationresource this_,
informationresource_viewings viewings3_,
Viewing currentvie1_
where
this_.id=viewings3_.informationresource_id
and viewings3_.viewings_id=currentvie1_.id
and this_.type='viewing'
and currentvie1_.id=?
Any hints that may help me advance with this issue? My current guess is that maybe I skipped some annotation definition that has been changed or modified since Hibernate 3, but so far I haven't been able to find anything illegal in the way I declare them - and my attempts to modify the #Join have been unsuccessful so far.
EDIT. After toying with this for some time, I have found that the issue may be related to the #DiscriminatorColumn of the abstract class. I have found that the problem lies that my type for this kind of request is never 'viewing', but 'directory'. In the old generated SQL I had both types generated:
this_.type in (
'viewing', 'directory'
)
But in the new sql this is constrained to 'viewing':
and this_.type='viewing'
I have changed in the new SQL this line, and it returns the right values that I need. The column type has only those two values, 'viewing' and 'directory'. So my question now is how to make Criteria to keep asking for the types there instead of forcing 'viewing' type.
Finally I found the solution, thanks to the hint I appointed in the EDIT block.
The solution came from establishing a formula in the base class:
#DiscriminatorFormula("case when type in ('viewing','directory') then 1 else 2 end")
And then changing in viewing resource the discriminator value annotation:
#DiscriminatorValue("1")
I really don't know why in Hibernate 3 I got all the values in the discrimination, and in Hibernate 4 the value was only this one, since the code had not changed at all. So if anyone in the future sees some similar behavior, maybe this trick can help you.

JPA - Eager - Lazy best practice

JBoss EAP 6
Hibernate 4
I have a J2EE application with a web browser client. ( Apache click )
Both the internal business logic and the client use the same entity objects.
I would like to have all relations in the entities set to lazy loading. This way I have good performance.
But when using the entities in the client ( that is the server side code of apache click ) I would need a lot of the relations to be eager loaded. The client code is accessing the back-end through a session bean.
So I have a couple of ways I can solve this:
Create 2 of each JPA entities, one with eager loading and one with lazy loading. And then use the one with eager loading in the client, and the one with lazy loading in the server. Most of the server logic will be in a transaction, so lazy loading is fine here.
Make all relations lazy loading. When accessing the entities from the client, make sure there is a transaction. ( #TransactionAttribute(TransactionAttributeType.REQUIRED) )
and code the access to the necessary fields so they are accessible after session bean call.
But that means that I have to start a transaction when that is not required, i.e. if I am only getting some objects. And I have to maintain more code. And I have to know exactly what relations the client needs.
Create an inheritance hierarchy, where I have a super entity, and then 2 child, one with objects relations lazy loaded, and one with only values, no objects. i.e. :
Super
#MappedSuperclass
public class SuperOrder {
#Id
#Column(name = "id")
#GeneratedValue(.....)
private Long id;
#Column(name = "invoice", length = 100)
private String invoice;
Child 1
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "testorder")
#SequenceGenerator(....)
public class Order extends SuperOrder {
#ManyToOne(targetEntity = PrintCustomerEnt.class, fetch = FetchType.EAGER, optional = true)
#JoinColumn(name = "print_customer_id", nullable = true)
#ForeignKey(name = "fk_print_customer")
#Valid
private PrintCustomerEnt printCustomer;
public PrintCustomerEnt getPrintCustomer() {
return printCustomer;
}
public void setPrintCustomer(final PrintCustomerEnt printCustomer) {
this.printCustomer = printCustomer;
}
}
Child 2
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "testorder")
#SequenceGenerator(...)
public class LazyOrder extends SuperOrder {
#Transient
private String printCustomerName;
#Column(name = "print_customer_id", nullable = true)
private Long printCustomerId;
What is the best practice... or is there something other good way to do this.
Basically the problem is I want to use the same entities in different scenarios. Sometimes I need eager loading, and sometimes I need lazy loading.
I suggest that you create just one JPA entity with lazy relationships, and when you need to load eagerly some of them create a Service that uses JPQL(HQL) to do some FETCH trick. The idea is one JPA entity and many services.
I've been programing in JPA 2 for some a while now, and I can say there are couple of now written rules that I almost always apply:
Use LAZY Inicialization on all your OneToMany, ManyToMany Relations
Use EAGER Inicalization on all your OneToOne, ManyToOne Relations
This rules apply on 99% of my projects. I think these are best practices due to my personal experience and some research I've been doing.
Note: I must say I do not use JOIN FETCH on Lazy Inicialization, instead I write a Prefetch Method. Example:
#Entity
class Entity{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
private Integer id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "mappedName",
orphanRemoval = true)
private List<Child1> collection1;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "mappedName",
orphanRemoval = true)
private List<Child2> collection2; }
And then we have the Controller:
class EntityController{
public Entity findCompraFolioFull(Integer id) {
EntityManager em = getEntityManager();
try {
Entity entity = em.find(Entity.class, id);
//Initialize Collections inside Transaccion, this prevents
//LazyInizialization No Proxy Exception later in code when calling
//hollow collections
cp.getCollection().size();
cp.getCollection().size();
return cp;
} finally {
em.close();
}
}
}
I don't recomend FETCH JOIN
public Entity findEntityByJoinFetch(Integer id) {
EntityManager em = getEntityManager();
try {
TypedQuery<Entity> tq = em.createQuery(
"SELECT e FROM Entity e\n"
+ "LEFT JOIN FETCH e.collection1\n"
+ "LEFT JOIN FETCH e.collection2\n"
+ "WHERE e.id = :id", Entity.class);
tq.setParameter("id", id);
return tq.getSingleResult();
} finally {
em.close();
}
}
Reasons I don't recomend Fetch Join Appoach:
If your collections are java.util.List type then this getSingleResult() will fail in hibernate due to lack of capacity to fetch MultipleBags without indexing notations on your OneToMany Relation.
You can always change the type of your collections to java.util.set in order to multiple bags to be fetched but this brings new kind of situations to deal with, Sets aren't ordered and HashCode() method won't work correctly so you'll have to #Override it inside Children Classes, and if you are using JAVAFX TableView to bind model to Items you won't be able to bind collections Set Type to Item Property of TableView, not directly at least.

Categories