How stop depth join hibernate in a query? - java

Hi I have this 3 Class:
public class A{
#ManyToOne
#JsonIgnore
private B b;
.....
}
public class B{
#OneToOne
#JsonIgnore
private C c;
.....
}
public class C{
.....
}
I have a findById(id) on my A class, and hibernate do a join to B class, and the it do another join to C class.
But I don't need to get C class' fields, so can I do??
Thank you

You could try to set max_fetch_depth hibernate property to a properly value.
From hibernate documentation:
Sets a maximum "depth" for the outer join fetch tree for single-ended associations (one-to-one, many-to-one). A 0 disables default outer join fetching.
e.g. recommended values between 0 and 3.
But keep in mind that this will affect your entire project.

I solved as suggested:
I add #OneToOne(fetch = FetchType.LAZY) because my filed isn't mandatory..

Related

Hibernate loads Lazy entities eagerly with native query

I was trying to optimise number of calls for my schema creational endpoint and get rid of n+1 problem. And I actually did it replacing them with only 2 calls. I have achieved it with Named Queries but I wonder if it is possible to do it with nativeQuery=true.
So, here is the situation:
Class A:
#Entity
#IdClass(AId.class)
#Table(name ="A")
#Data
class A implements Serializable{
#Id
#Column(name = "ID")
private Integer id;
// code omitted...
#ManyToOne(fetch=FetchType.Lazy)
#JoinColumns(
...
)
private B b;
}
Class B:
#Entity
#IdClass(AId.class)
#Table(name ="B")
#Data
class B implements Serializable{
#Id
#Column(name = "ID")
private Integer id;
// code omitted...
#OneToMany(mappedBy="b", cascade=Cascade.ALL, fetch=FetchType.Lazy)
#JoinColumns(
...
)
private List<A> aList;
}
The problem occurs when I try to fetch the data with generated or native queries.
It grabs B entities when I fetch A though it's Lazy for A.
Expected behaviour is the executing a query as follows:
Hibernate:
/* dynamic native SQL query */ SELECT
*
FROM
A a
WHERE
a.ID IN (
?
)
But right after this (no matter how I played with dynamic native query) I have one more query for B entity that I don't need:
Hibernate:
/* load com.example.to.B */ select
b0_.id as id1_1_0_,
from
B b0_
where
b0_.id=?
Why is this so and is there any way to avoid it?
Thanks in advance.
Set a breakpoint in e.g. org.hibernate.resource.jdbc.internal.EmptyStatementInspector#inspect to see which code triggers the lazy initialization. Maybe it's your debugging that triggers this through a toString implementation.
Hibernate cannot fetch lazily for ToOne relationships.
The field b can be null in A, and hibernate has to check with the table b before confirming to populate the field with null. The query for B you observed is the result.
You may consider using #MapsId, e.g.:
#ManyToOne
#MapsId(“id”)
private B b;
You may read further about #MapsId here:
https://www.objectdb.com/api/java/jpa/MapsId

Hibernate.initialize exception - Cutting dependency chain

I have a Class A which has an object of Class B which has an object of Class C. I want to get object of class B from object of class A without getting object of class C in b. (I have , and want to keep it this way, everything with lazy loading)
I am doing:
Hibernate.initialize(a.getObjectOfClassB());
But get exception. Is there any way to do what i want? Cutting the hibernate initialize chain?
Thanks in advanced!
So your entity structures appear to be mapped as follows:
public class EntityA {
#OneToMany(mappedBy = "a")
private List<EntityB> bList;
}
public class EntityB {
#ManyToOne
private EntityA a;
#OneToMany(mappedBy = "b")
private List<EntityC> cList;
}
public class EntityC {
#ManyToOne
private EntityB b;
}
So you have a specific EntityA that you want to fetch it's associated EntityB instances. You can obtain that list either at query time or as a post initialization step.
The important thing to note here is that the mappings between A - B - C are using #OneToMany which are lazily fetched by default.
To do this at query time:
SELECT a
FROM EntityA a
JOIN FETCH EntityB b
WHERE a.id = :entityAId
The returned EntityA already has your List<EntityB> already loaded for you and you need to do nothing else.
To do this as a post initialization step after you've fetched a single EntityA instance.
Hibernate.initialize(entityA.getBList());
or
entityA.getBList().size();

Eclipselink lazy loading issue for objects with discriminator column

We have following hierarchy in our application:
#MappedSuperclass
public abstract class AbstractDemandOrMeasureBE {
}
#Entity
#Inheritance
#DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.INTEGER)
#Table(name = "V_VIEW2")
public abstract class AbstractDemandOrConcreteMeasureBE extends AbstractDemandOrMeasureBE {
#Column(name = "VC_ID")
private Long vcId;
}
#Entity
#DiscriminatorValue("2")
public class MinimalDemandBE extends AbstractDemandOrConcreteMeasureBE {
..
}
#Entity
#DiscriminatorValue("1")
#HasRelationsAnnotatedAsLazyLoaded
public class ValidationMeasureBE extends AbstractDemandOrConcreteMeasureBE {
..
}
In other object I am trying to load those entities like that:
#Table(name = "V_VIEW2")
public class VCBE extends SomeVeryAbstractBE {
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "VC_ID")
private List<ValidationMeasureBE> validationMeasures;
public transient static final String ATTRIBUTE_VALIDATION_MEASURES = "validationMeasures";
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "VC_ID")
private List<MinimalDemandBE> minimalDemands;
public transient static final String ATTRIBUTE_MINIMAL_DEMANDS = "minimalDemands";
There is a precompiled query to load all hierarchy, which load some other parent objects. There is also a hint for the query - eclipselink.left-join-fetch=PP.VCBE.validationMeasures (if this is changed to eclipselink.left-join-fetch=PP.VCBE.minimalDemands, then minimal demands are loaded, but validation measures (entries with discriminator 1) are also loaded into the minimal demands collection - but those should not be loaded).
Now, when query is executed validationMeasures collection if filled with objects, but all those object are actually minimal demands and have 2 as a discriminator value in the database.
The query, which gets executed is following:
SELECT * FROM V_VIEW1 t1
LEFT OUTER JOIN V_VIEW0 t0 ON (t0.PP_D = t1.ID)
LEFT OUTER JOIN V_VIEW2 t2 ON (t2.VC_ID = t0.ID)
WHERE (((t1.ID = ?) AND (t1.HP_ID = ?))
AND t1.HP_IS IN (SELECT t3.ID FROM V_VIEW t3 WHERE (t3.HWPG_ID = ?)))
bind => [3 parameters bound]
As I can see there is no DISCRIMINATOR constraint in the query, why?
Any ideas of such a behavior? And how can I tell eclipselink to load collection, depending on discriminator value?
Can you include the JPQL query and hints you use to get this SQL.
So, you are saying it works when you use a join-fetch, but not a left-join-fetch?
This seems like it may be a bug, that the inheritance discriminator expression is not being included when using an outer join. If this is the case, please log a bug for this and vote for it.
Your model is very odd though. Why split the two subclasses into two separate relationships? Having one would be much more efficient. Or if you do split them, you should be using different foreign keys, not the same one. Sharing the same foreign key for two different relationships is probably not a good idea.

JPA: uni-directional OneToMany question

I have the following classes:
class A{
#OneToOne(cascade=CascadeType.ALL)
private B b;
}
class C{
#ManyToOne
private A a;
}
class B{
#OneToOne
private A a;
#MapKey(name = "name")
#OneToMany(cascade = CascadeType.ALL, ...)
#JoinColumn(...)
private Map<String C> cs;
}
How do I have to specify the mapping on B.cs to join where B.a == C.a?
Is this possible? Or do I have to change the property C.a to C.b? (I would prefer to keep it as it is, as the entity B is just a helper class.)
I also tried to change B to #Embeddable, but Map is not supported for embeddables.
JPA requires that all relationships be by Id (the foreign key references the primary key).
So, you need to either add a #ManyToOne from C to B.
Or, ensure that B's Id is the foreign key to A (add #Id on the #OneToOne from B to A and remove A's other #Id).
If B was a subclass of A instead of having a OneToOne this would also work.
If you are using EclipseLink, you can defined more complex criteria for a relationship. You would need to define the OneToMany's foreign keys using a DescriptorCustomizer and the OneToManyMapping API.
I think you can extends B from A.
If this doesn't work for you, maybe you can add a transient property to refer A's id,
#Transient
Integer getId1() {
return a.getId();
}
and join C using id1 instead of B's primary key.
Edit: This doesn't work.

Hibernate custom join clause on association

I would like to associate 2 entities using hibernate annotations with a custom join clause. The clause is on the usual FK/PK equality, but also where the FK is null. In SQL this would be something like:
join b on a.id = b.a_id or b.a_id is null
From what I have read I should use the #WhereJoinTable annotation on the owner entity, but I'm puzzled about how I specify this condition...especially the first part of it - referring to the joining entity's id.
Does anyone have an example?
Here's an example using the standard parent/child paradigm that I think should work using the basic #Where annotation.
public class A {
...
#ManyToOne(fetch = FetchType.EAGER) // EAGER forces outer join
#JoinColumn(name = "a_id")
#Where(clause = "a_id = id or a_id is null") // "id" is A's PK... modify as needed
public B getB() { return b; }
}
public class B {
...
#OneToMany(mappedBy = "b")
public List<A> getA() { return a; }
}

Categories