Hibernate java getting a complete object - java

I want to get the complete A object from database, this include the B object that contains the C and D.
I have A B C D classes
class A
private B object
Class B
private List<C> objects
Class C
private List<D> objects
This is what I do:
Session session = sf.openSession();
String consulta = "select a from A a;
Query q = session.createQuery(consulta);
List<A> aaaa= q.list();
This is getting the A with B, but B is not containing the list of C.
Thanks for helping

Use JOIN FETCH in your query to get everything in one go:
Query q = "select b from B b join fetch b.c";
This addresses the N+1 problem that you would have if you initialized everything lazily.

Related

How to fetch object using the List Association in Hibernate

I have a class A with setters and getters
class A{
private int id;
private List<B> b;
}
I want to fetch the A object based on the B objects. So suppose I have a list of B objects I want to get the A objects that contain the B.
So i decided to use in
Here is the code
Criteria criteria = session.createCriteria(A.class).setCacheable(false);
criteria.add(Restrictions.in("b",{list of B})).list();
This gives an error java.sql.SQLException: No value specified for parameter 1
How can I get object A using B
You should join the B's first:
Criteria criteria = session.createCriteria(A.class)
.setCacheable(false)
.setFetchMode("bList", FetchMode.JOIN)
.createAlias("bList", "b");
and then use an IN for the ids of b:
criteria.add(Restrictions.in("b.id",{list of B})).list();
Set your fetch mode accordingly whether you want the list of B's also apart from A.

Update Entity Relationship via UPDATE .. SET Query

I have two entities:
class A {
#OneToMany(mappedBy = "a")
List<B> bs;
// getter/ setter
}
class B {
#ManyToOne
A a;
// getter/ setter
}
To delete one b, I first need to invalidate that relationship.
"Traditionally" I would do something like that:
A a = em.getReference(A.class, entityIdA)
B b = em.getReference(B.class, entityIdB);
a.getBs().remove(b);
b.setA(null);
em.remove(b);
This is not very performant, if the List of a's is getting large (a few hundreds in my case).
I know I can also use JPQL to create an update query.
something like this:
Query q = em.createQuery("UPDATE B b SET b.a = NULL");
q.executeUpdate();
Question: What would be the corresponding JPQL query to remove one b from a's list of bs?
In short:
How to translate
a.getBs().remove(b);
into a JPQL query?
EDIT: the mentioned update query translates to
UPDATE B SET A_ID = ? WHERE (ID = ?)
bind => [null, 2]
Tables look like this:
A
ID
B
ID A_ID
From the comments and from this question, changing the owning side of the relationship is sufficient.
Therefore, to do
a.getBs().remove(b);
as an jpql query, one can do
"UPDATE B b SET b.a = NULL"
This will release the bidirectional relationship between a and b.
Note that you might need to clear the L2 cache or close the EntitiyManagerFactory for this to take effect.
factory.getCache().evictAll();

Cannot create Typed Query for query with more than one return using request result type

I'm trying to bind oracle result list to a summary list. But my summary list has 3 classes defined as entities of DB
I have three entity classes A, B, C
Summary.class
{
#Autowired
private A a;
#Autowired
private B b;
#Autowired
private C c;
//getters and setters
}
#Enity
class A{
Fields 1..n ;
} // same goes for other classes definition
I get the results with following query, but the results cannot be cast to the Summary object
List<Summary> summaryList = entityManager.createQuery("from A a, B b, C c" +
" where a.field1 = b.field1 and a.fValue = :fValue " +
"and b.field3= c.field3", Summary.class)
.setParameter("fValue ", fValue )
.getResultList();
Debugging:
I made sure resultslist is not empty and below query works fine if I dont cast it to an object
List summaryList = entityManager.createQuery("from A a, B b, C c" +
" where a.field1 = b.field1 and a.fValue = :fValue " +
"and b.field3= c.field3")
.setParameter("fValue ", fValue )
.getResultList();
The alternative 1 I see is to iterate through summaryList and assign it them to individual lists like this, which I haven't tested yet but I think it might give a class cast exception since the casting dint work before
for (int i = 0; i < summaryList.size(); i++) {
Summary s= (Summary) summaryList.get(i); // might be class cast Exception
aList.add(s.getA());
bList.add(s.getB());
}
The alternative 2 I'm thinking is to
get only class A fields list from db cast it to A's List, do it 3 times brute force till I get all of them.
Below are some of questions I looked at before creating a new question
Uses a different class to combine multiple entity classes
gets a list back mapped to pojo
Please let me know your thoughts, I'm thinking my main approach is good way to do it if it works.
Your JPQL select statement "from A a, B b, C c" can not be mapped back to Summary entity, JPA does not have enough info to do that.
If in your logic, a summary instance can be composed from A, B, C then you can have a constructor like
public Summary(A a, B b, C c) {
.............
}
and changed your select statment to be
"select new Summary(a, b, c) FROM A a, B b, C c"

How to join one table with different tables with criteria API?

I have following classes:
class A {
private B b;
// getters/setters
}
class B {
private C c;
private D d;
// getters/setters
}
class C {
private boolean outdated;
// getters/setters
}
class D {
// not important fields
// getters/setters
}
Class B is connected to A, C and D with relation 'one-to-one'.
I am trying to join following tables with criteria api.
I have following code:
Root<A> root = query.from(A.class);
root.join(A_.b)
.join(B_.c)
.join(B_.d);
But unfortunately this code will not compile, I will get error on line with ".join(B_.d)", because after joining B with C I cannot use fields of B for joining.
The reason why I want to make such joins is because I need to have condition that entity C is not outdated (so I will add 'on' condition for it).
Does anybody know how to solve this problem?
root.join(A_.b).join(B_.c) represents a C, so there is no way then to join to "B_.d". You would need to do
Root<A> root = query.from(A.class);
Join<A,B> bJoin = root.join(A_.b);
bJoin.join(B_.c);
bJoin.join(B_.d);

JPA left/right join query

I have this structure from entities Aa, Bb, Cc:
Aa has a list of Bb
Bb has a list of Cc
-
public class Aa{
#OneToMany
List<Bb> listBb;
}
public class Bb{
#OneToMany
List<Bb> listCc;
}
I would like to create a JPA Criteria API query to pool Aa by an id of C:
public A getAaByCcId(long id) {...}
In native sql I would have try left join (twice). How do I do this using JPA?
You also do it with joins in JPQL:
select a from Aa a
inner join a.listBb b
inner join b.listCc c
where c.id = :cId
Note that inner joins can be used here, since you have a restriction on c.id = :cId, which can only be true if B and C exist. But you could use left joins as well.
EDIT:
Using a Criteria query, it would look like the following (not tested):
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Aa> criteria = builder.createQuery(Aa.class);
Root<Aa> a = criteria.from(Aa.class);
CollectionJoin<Aa, Bb> b = a.join(Aa_.listBb);
CollectionJoin<Bb, Cc> c = b.join(Bb_.listCc);
criteria.where(builder.equal(c.get(Cc_.id), cId));
return em.createQuery(criteria).getResultList();
Assuming that each entity has a reference to its parent entity, where Cc's reference to a Bb is called bb and Bb's reference to an Aa is called aa, then in JPQL, you can do:
select cc.bb.aa from Cc cc where cc.id = ?
The criteria version of this should be a simple translation.

Categories

Resources