Quero fazer uma projeção no atributo de objeto de uma entidade com o Hibernate Criteria 6.
Aqui estão meus modelos:
@Entity
public class MyAuthor {
private String id;
private String name;
private int nbBooks;
private Date birthDate;
@Embedded
private MyAddress address;
}
@Embeddable
public class MyAddress {
private String street;
private MyCity city;
}
@Entity
public class MyCity {
String id;
String name;
}
Aqui está meu teste de unidade:
// We populate data with CITY_1 & CITY_2, ADDR_1 on CITY_1, ADDR_2 on CITY_1 and ADDR_3 on CITY_2 with @Before
CriteriaBuilder criteriaBuilder = sessionFactory.getCurrentSession().getCriteriaBuilder();
CriteriaQuery<MyCity> query = criteriaBuilder.createQuery(MyCity.class);
Root<MyAuthor> root = query.from(MyAuthor.class);
Join<MyAuthor, MyAddress> from = root.join("address", JoinType.LEFT);
// produce this request : select c1_0.id,c1_0.name from MyAuthor ma1_0 left join MyCity c1_0 on c1_0.id=ma1_0.city_id where c1_0.name is not null
query.select(from.get("city"))
.where(criteriaBuilder.isNotNull(from.get("city").get("name")));
// produce the same request : select c1_0.id,c1_0.name from MyAuthor ma1_0 left join MyCity c1_0 on c1_0.id=ma1_0.city_id where c1_0.name is not null
// query.multiselect(from.get("city").get("id"), from.get("city").get("name"))
// .where(criteriaBuilder.isNotNull(from.get("city").get("name")));
// with the query.select(), there are 2 results, with the multiselect there are 3.
List<MyCity> cities = sessionFactory.getCurrentSession().createQuery(query).getResultList();
assertEquals(3, cities.size());
Não entendo como o SQL gerado é o mesmo MAS o comprimento do resultado é diferente.
Alguma ideia? Muito obrigado.
Embora a consulta que está sendo gerada seja a mesma, o processamento real do resultado é diferente.
Se você executasse essa consulta diretamente com sua ferramenta de banco de dados ou uma ferramenta de banco de dados como o DBWeaver, provavelmente obteria 3 linhas de dados. (Como você disse, você tinha 9 autores, dos quais 3 tinham uma cidade).
Dessas 3 linhas de dados, 2 serão iguais, pois os autores provavelmente moram na mesma cidade.
Agora, ao utilizar,
select
o que você obtém é uma lista deMyCity
entidades únicas. Que, neste caso, são dois valores reais. Ao processar o resultado, o Hibernate mapeia os resultados para um valor,MyCity
mas antes de fazer isso, verifica se já possui um valorMyCity
com esse valor exatoid
em seu cache.Ao utilizá-lo,
multiselect
ele retornará as linhas do resultado como estão, como uma lista de tuplas. Basicamente, uma lista glorificadaObject[]
, que conterá todas as 3 linhas, até mesmo os dados duplicados.Do Javadoc de
multiselect
(ênfase minha)