Working with Joins¶
TorpedoQuery makes it easy to create joins between entities. Joins are essential when your data is spread across multiple tables or entities.
Inner Joins¶
An inner join returns records that have matching values in both tables.
Basic Inner Join¶
Entity entity = from(Entity.class);
SubEntity subEntity = innerJoin(entity.getSubEntity());
Query<Entity> query = select(entity);
Generated HQL: SELECT entity_0 FROM Entity entity_0 INNER JOIN entity_0.subEntity subEntity_1
Selecting from Joined Entities¶
Entity entity = from(Entity.class);
SubEntity subEntity = innerJoin(entity.getSubEntity());
Query<Object[]> query = select(entity.getCode(), subEntity.getCode());
Generated HQL: SELECT entity_0.code, subEntity_1.code FROM Entity entity_0 INNER JOIN entity_0.subEntity subEntity_1
Joining with Collections¶
You can join with collection relationships:
Entity entity = from(Entity.class);
SubEntity subEntity = innerJoin(entity.getSubEntities());
Query<Entity> query = select(entity);
Generated HQL: SELECT entity_0 FROM Entity entity_0 INNER JOIN entity_0.subEntities subEntity_1
Left Joins¶
A left join returns all records from the left table and the matched records from the right table. The result is NULL from the right side if there is no match.
Entity entity = from(Entity.class);
SubEntity subEntity = leftJoin(entity.getSubEntity());
Query<Entity> query = select(entity);
Generated HQL: SELECT entity_0 FROM Entity entity_0 LEFT JOIN entity_0.subEntity subEntity_1
Right Joins¶
A right join returns all records from the right table and the matched records from the left table. The result is NULL from the left side if there is no match.
Entity entity = from(Entity.class);
SubEntity subEntity = rightJoin(entity.getSubEntity());
Query<Entity> query = select(entity);
Generated HQL: SELECT entity_0 FROM Entity entity_0 RIGHT JOIN entity_0.subEntity subEntity_1
Multiple Joins¶
You can create multiple joins in a single query:
Entity entity = from(Entity.class);
SubEntity subEntity = innerJoin(entity.getSubEntity());
SubEntity subEntities = innerJoin(entity.getSubEntities());
Query<Entity> query = select(entity);
Generated HQL: SELECT entity_0 FROM Entity entity_0 INNER JOIN entity_0.subEntity subEntity_1 INNER JOIN entity_0.subEntities subEntity_2
Multiple Joins on the Same Property¶
You can also join the same property multiple times:
Entity entity = from(Entity.class);
innerJoin(entity.getSubEntity());
leftJoin(entity.getSubEntity());
Query<Entity> query = select(entity);
Generated HQL: SELECT entity_0 FROM Entity entity_0 INNER JOIN entity_0.subEntity subEntity_1 LEFT JOIN entity_0.subEntity subEntity_2
Conditions on Joined Entities¶
You can add where conditions on joined entities:
Entity entity = from(Entity.class);
SubEntity subEntity = innerJoin(entity.getSubEntities());
where(subEntity.getCode()).eq("test");
Query<Entity> query = select(entity);
Generated HQL: SELECT entity_0 FROM Entity entity_0 INNER JOIN entity_0.subEntities subEntity_1 WHERE subEntity_1.code = :code_2
WITH Clause (Join Conditions)¶
The WITH clause allows you to specify conditions directly on the join:
Entity entity = from(Entity.class);
SubEntity subEntity = innerJoin(entity.getSubEntities());
with(subEntity.getCode()).eq("test");
Query<Entity> query = select(entity);
Generated HQL: SELECT entity_0 FROM Entity entity_0 INNER JOIN entity_0.subEntities subEntity_1 WITH subEntity_1.code = :code_2
Complex WITH Conditions¶
You can create complex join conditions:
Entity entity = from(Entity.class);
SubEntity subEntity = innerJoin(entity.getSubEntities());
OnGoingLogicalCondition withCondition =
condition(subEntity.getCode()).eq("test").or(subEntity.getCode()).eq("test2");
with(withCondition);
Query<SubEntity> query = select(subEntity);
Generated HQL: SELECT subEntity_1 FROM Entity entity_0 INNER JOIN entity_0.subEntities subEntity_1 WITH ( subEntity_1.code = :code_2 OR subEntity_1.code = :code_3 )
Custom Entity Joins¶
TorpedoQuery also allows joining unrelated entities with custom conditions:
Entity entity = from(Entity.class);
Entity2 entity2 = innerJoin(Entity2.class).on(query2 -> {
return condition(query2.getCode()).eq(entity.getCode());
});
Query<Entity> query = select(entity);
Generated HQL: SELECT entity_0 FROM Entity entity_0 INNER JOIN Entity2 entity2_1 ON entity2_1.code = entity_0.code
Custom Entity Joins with Multiple Conditions¶
Entity entity = from(Entity.class);
Entity2 entity2 = innerJoin(Entity2.class).on(query2 -> {
return condition(query2.getCode()).eq(entity.getCode())
.and(query2.getVar()).eq("test");
});
Query<Entity> query = select(entity);
Generated HQL: SELECT entity_0 FROM Entity entity_0 INNER JOIN Entity2 entity2_1 ON entity2_1.code = entity_0.code AND entity2_1.var = :var_2
Joining Maps¶
You can also join with map collections:
Entity entity = from(Entity.class);
SubEntity innerJoin = innerJoin(entity.getSubEntityMap());
Query<SubEntity> query = select(innerJoin);
Generated HQL: SELECT subEntity_1 FROM Entity entity_0 INNER JOIN entity_0.subEntityMap subEntity_1
Advanced Example¶
Here's a comprehensive example that showcases a chain of joins:
User from = from(User.class);
City city = innerJoin(from.getCity());
with(city.getCode()).in("one", "two").or(city.getCode()).notIn("three", "four");
District district = innerJoin(city.getDistrict());
with(district.getCode()).notIn("exclude1", "exclude2");
State state = innerJoin(district.getState());
with(state.getCode()).eq("AP").or(state.getCode()).eq("GUJ").or(state.getCode()).eq("KTK");
with(state.getCountry().getCode()).eq("india");
Query<User> select = select(from);
This example shows how to join multiple entities together with conditions on each join, creating a complex but readable query.