Let's say I have the following SQL:
select * from table1
inner join table2 on table1.id = table2.table1id;
inner join table3 on table2.id = table3.table2id;
inner join table4 on table3.id = table4.table3id;
and I have Java entities like table1, table2, table3 and table4.
I want to map this query using criteria API. In order to do that I created class Table5 which contains all of fields of all classes.
Then I created a repository with the method:
public List<Table5> getAllTable5 () {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Table5> query = cb.createQuery(Table5.class);
Root<Table1> root = query.from(Table1.class);
Join<Table1, Table2> table1Table2Join= root.join(Table1_.TABLE2);
Join<Table2, Table3> table2Table3Join= root.join(Table2_.TABLE3);
Join<Table3, Table4> table3Table4Join= root.join(Table3_.TABLE4);
query.multiselect(
root.get // all fields
);
TypedQuery<Table5> typedQuery = em.createQuery(query);
return typedQuery.getResultList();
}
Is it possible to create class like:
class Table5 {
private Table1 table1;
private Table2 table2;
private Table3 table3;
private Table4 table4;
// getters setters constructors
}
If yes, how should getAllTable5 method look like?
You can either select every table entity, or select just the first one and rely on join fetching.
public List<Table5> getAllTable5 () {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Table1> query = cb.createQuery(Table1.class);
Root<Table1> root = query.from(Table1.class);
query.select(root);
TypedQuery<Table1> typedQuery = em.createQuery(query);
EntityGraph entityGraph = em.createEntityGraph();
// Apply subgraphs for the associations to fetch
typedQuery.setHint("javax.persistence.loadgraph", entityGraph);
List<Table1> list = typedQuery.getResultList();
List<Table5> table5s = new ArrayList<>(list.size());
for (Table1 t : list) {
table5s.add(new Table5(t, t.getTable2(), , t.getTable2().getTable3(), , t.getTable2().getTable3().getTable4());
}
return table5s;
}
Related
I'm trying to sort a list by the max date of a children class, using hibernate criteria:
Domain:
class Entity {
List<Children> childrens;
}
class Children {
Date date
}
Something like this in SQL:
SELECT
*
FROM
entity
INNER JOIN
children c1 ON c1.entity_id = entity.id
WHERE
c1.date =
(SELECT MAX(c2.date) FROM children c2 WHERE c2.entity_id = c1.entity_id)
ORDER BY
c1.date DESC
Does anyone know how to do this?
You can formulate something like that with HQL or the JPA Criteria API. Here is the HQL version:
from
Entity e
order by
(select max(c.date) from e.children c) desc
or with the Criteria API:
CriteriaBuiler cb = em.getCriteriaBuilder();
CriteriaQuery<Entity> q = cb.createQuery(Entity.class);
Root<Entity> r = q.from(Entity.class);
Subquery<Date> s = q.subquery(Date.class);
Join<?, ?> c = s.correlate(r).join("children");
s.select(cb.max(c.get("date")));
q.orderBy(cb.desc(s));
List<Entity> list = em.createQuery(q).getResultList();
I have got 2 tables TABLE_A & TABLE_B. I have got 2 entity classes for these 2 tables named TableA & TableB.
TableA has got an attribute which is actually a foreign key, is ID of TableB. But this relation is not there at table level as well as entity class level.
Which means that these two tables are unrelated with respect to entity manager.
Now I want to generate a jpa query like below
select
tablea.name, tableb.name
from TableA tablea left join TableB tableb on
tablea.tablebId=tableb.pkId
Basically Table_A is my main table.
Here is what I have trie, this is doing cross join
String rootClassNameWithPackage = "TableA";
String fkClassNameWithPackage = "TableB";
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<?> criteriaQuery = null;
Root<?> rootTable = null;
Root<?> fkTable = null;
try {
criteriaQuery = criteriaBuilder.createQuery(String.class);
rootTable = criteriaQuery != null ? criteriaQuery.from(Class.forName(rootClassNameWithPackage)) : null;
fkTable = criteriaQuery != null ? criteriaQuery.from(Class.forName(fkClassNameWithPackage)) : null;
List<Predicate> criteriaList = new ArrayList<>();
Predicate predicateSearchFk = criteriaBuilder.equal(rootTable.get("tablebId"), fkTable.get("pkid"));
criteriaList.add(predicateSearchFk);
criteriaQuery.where(criteriaBuilder.and(criteriaList.toArray(new Predicate[0])));
} catch (ClassNotFoundException e) {
logger.error(e.getMessage());
}
final TypedQuery<?> query = entityManager.createQuery(criteriaQuery);
query.setMaxResults(pageSize);
return query.getResultList();
As mentioned earlier, this is doing cross join. We want to left join. Unfortunately we cant change the entity classes to add the FK relationships.
I have two entities, ShoppingCart and ShoppingCartLine. ShoppingCart has a collection of ShoppingCartLines. I am trying to create a JPA query using criteria to get a list of ShoppingCart ids and the number of ShoppingCartLines each ShoppingCart has.
Here is the mapping in the ShoppingCart class:
#OneToMany(mappedBy = "shoppingCart", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval=true)
private Set<ShoppingCartLine> shoppingCartLines = new TreeSet<ShoppingCartLine>();
Here is the code I am attempting to create my JPA query with:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<ShoppingCart> carts = cq.from( ShoppingCart.class );
Join<ShoppingCart, ShoppingCartLine> lines = carts.join( "shoppingCartLines", JoinType.LEFT);
cq.multiselect( carts.<Long>get( "id" ), cb.count( lines ));
cq.groupBy( carts.<Long>get("id") );
Query tq = em.createQuery( cq );
return tq.getResultList();
When I run this I get an SQLGrammerException, the SQL produced does not look correct to me.
select
shoppingca0_.id as col_0_0_,
count(.) as col_1_0_
from
SHOPPINGCART shoppingca0_
left outer join
SHOPPINGCARTLINE shoppingca1_
on shoppingca0_.id=shoppingca1_.shoppingCart_id,
SHOPPINGCARTLINE shoppingca2_
where
shoppingca0_.id=shoppingca2_.shoppingCart_id
group by
shoppingca0_.id
I should mention I am using Hibernate 3.5.4 with MySQL5Dialect
This is the query I am wanting to generate:
select
sc.id,
count(scl.id)
from
shoppingcart sc
left join
shoppingcartline scl
on
scl.shoppingCart_id = sc.id
group by
sc.id
Any idea what I'm doing wrong? Thanks.
Try to replace join and multiselect lines with
SetJoin<ShoppingCart, ShoppingCartLine> lines =
carts.joinSet( "shoppingCartLines", JoinType.LEFT);
cq.multiselect( carts.<Long>get( "id" ), cb.count( lines.<Long>get( "id" ) ));
I am having problem creating criteriaQuery for the following sql.
Any help would be appreciated.Lets say I have two tables Member and Person.
I am joining on name and age and having where clause for both of the table.
I am using OpenJPA(2.0)
select *
from Member
join Person
on Member.name = Person.name
and Member.age = Person.age
where Member.name = 'someOne'
and Member.age = '24'
and Person.gender = 'F'
and Person.type = 'employee'
How about something like this:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Tuple> criteria = builder.createTupleQuery();
Root<Member> fromMember = criteria.from(Member.class);
Root<Person> fromPerson = criteria.from(Person.class);
criteria.multiselect(fromMember, fromPerson);
List<Predicate> predicates = new ArrayList<Predicate>();
predicates.add(builder.equal(fromMember.get(Member_.name), fromPerson.get(Person_.name)));
predicates.add(builder.equal(fromMember.get(Member_.age), fromPerson.get(Person_.age)));
predicates.add(builder.equal(fromMember.get(Member_.name), "someOne"));
predicates.add(builder.equal(fromMember.get(Member_.age), 24));
predicates.add(builder.equal(fromPerson.get(Person_.gender), "F"));
predicates.add(builder.equal(fromPerson.get(Person_.type), "employee"));
criteria.where(predicates.toArray(new Predicate[predicates.size()]));
List<Tuple> result = em.createQuery(criteria).getResultList();
This will return a 2-element tuple made up of Member and Person. You can enumerate the individual fields in the call to multiselect if you would rather have individual fields in each tuple.
How to express the exists clause with JPA?
First (we are on Oracle and have a DUAL Table):
#Entity()
#Table(name = "DUAL")
#ReadOnly
public class Dual {
#Id
String dummy;
public String getDummy() {
return dummy;
}
}
Then:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Dual> cq = cb.createQuery(Dual.class);
Subquery<ProtokollSatz> sq = cq.subquery(ProtokollSatz.class);
Root<ProtokollSatz> root1 = sq.from(ProtokollSatz.class);
sq.where(
cb.and(
cb.equal(root1.<Integer> get("field1"), Integer.valueOf(field1)),
cb.equal(root1.<Integer> get("field2"), Integer.valueOf(field2))));
cq.where(cb.exists(sq));
TypedQuery<Dual> query = em.createQuery(cq);
boolean ifExists = query.getResultList().size() > 0;
You get:
SELECT t0.DUMMY FROM DUAL t0 WHERE EXISTS
(SELECT ? FROM PROTOKOLL_SAETZE t1 WHERE ((t1.FIELD1 = ?) AND (t1.FIELD2 = ?)))
Tested with eclipselink.
Exists is perfectly legal in JPQL, just use it. Perhaps I don't understand the question though? It's a bit terse :)
SELECT user
FROM SOUsers user
WHERE EXISTS (SELECT user0
FROM SOUsers user0
WHERE user0 = user.bestFriendWhoAnswersTheirQuestions
and user0.name = 'Roman')