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);
Related
I have a following query where I join tables A,B, and C:
C is related to B via C.B_ID
B is related to A via B.A_ID
I want to retrieve a report, where for each C, I want to retrieve also fields from corresponding B and A.
If only a subset of fields is required, a projection and fetching to a POJO (with required properties from C, B, A) is an obvious approach.
class CReportDTO {
Long c_id;
Long c_field1;
Long c_bid;
Long b_field1;
// ...
CReportDTO(Long c_id, Long c_field1, Long c_bid, Long b_field1) {
// ...
}
// ..
}
public List<CReportDTO> getPendingScheduledDeployments() {
return dslContext.select(
C.ID,
C.FIELD1,
C.B_ID,
B.FIELD1,
B.A_ID
A.FIELD1,
A.FIELD2
)
.from(C)
.join(B)
.on(C.B_ID.eq(B.ID))
.join(A)
.on(B.A_ID.eq(A.ID))
.fetchInto(CReportDTO.class);
};
}
My question
In case where all fields are needed I would prefer to have my report DTO contain A, B, C POJOs, without flattening them out:
class CReportDTO2 {
C c;
B b;
A a;
CReportDTO2(C c, B b, A a) {
// ...
}
// ..
}
Is it possible to modify my query to:
include all fields from each table
massage it into CReportDTO2 without too much verbosity
You can use a lesser known feature of jOOQ's DefaultRecordMapper by aliasing your fields using a dot notation that denotes the nesting structure of your DTO:
public List<CReportDTO> getPendingScheduledDeployments() {
return dslContext.select(
// Add these vvvvvvvvvvvvvvvvvvvv
C.ID .as("c.c_id"),
C.FIELD1 .as("c.c_field1"),
C.B_ID .as("c.b_id"),
B.FIELD1 .as("b.b_field1"),
B.A_ID .as("b.a_id")
A.FIELD1 .as("a.a_field1"),
A.FIELD2 .as("a.a_field2")
)
.from(C)
.join(B)
.on(C.B_ID.eq(B.ID))
.join(A)
.on(B.A_ID.eq(A.ID))
.fetchInto(CReportDTO2.class);
}
See Javadoc
If Field.getName() is MY_field.MY_nested_field (case-sensitive!), then this field's value will be considered a nested value MY_nested_field, which is set on a nested POJO
Note that this doesn't work with the constructor you've provided. You'll have to provide a default constructor as well, and make your fields non-final (in case they are).
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"
Lets say i have following code:
#Embeddable
Class Xyz { // has only one field
private String value;
}
#Entity
Class B {
#Embedded
private Xyz xyz;
}
#Entity
Class C {
private B b;
}
Now in my CDao method - getAllByXyz(List<String> values) I would like to get all C entries from db where c.b.xyz.value is in values. Here is what i got:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<C> q = cb.createQuery(C.class);
Root<C> r = q.from(C.class);
q.select(r);
Join<C, B> join = r.join(C_.b);
Expression<String> e = r.get(B_.xyz);
Predicate p = e.in(values);
q.where(p);
return em.createQuery(q).getResultList();
The error says Object comparisons can only use the equal() or notEqual() operators. As far as I understood there is problem connected with Xyz class and value field. How can I fix this?
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.
Given a class:
class MyClass {
private String a;
private String b;
private String c;
}
and code like so:
Query q = getEntityManager()
.createNativeQuery('select a, b from table', MyClass.class);
It throws an exception. My solution is to add
'' as c
in the sql. However, the c in MyClass is a variable that I intend to put some calculated value into, and that c does not have any real mapping to the table, so the solution just puts the c with a blank value...
My question is, are there any alternatives?
You need to mark c as #Transient so that it is not mapped.