Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

128
Visualizações
Asignar el resultado de la consulta con la unión filtrada a la entidad con relación

Estoy tratando de realizar una consulta SQL con una unión, donde la unión tiene una condición de filtro adicional. Usando SQL simple, mis datos se modelan así:

 create table food_storage ( name varchar primary key ); create table food ( name varchar primary key, expired bool, stored_in varchar references food_storage(name) ); insert into food_storage (name) values ('drawer'), ('fridge'), ('cabinet'); insert into food (name, expired, stored_in) values ('teabags', false, 'drawer'), ('beans', true, 'drawer'), ('leftovers', true, 'fridge'), ('rice', false, 'cabinet'), ('flour', false, 'cabinet');

Y mi consulta se ve así (solo seleccionando algunos campos por brevedad):

 select food_storage.name, food.name from food_storage left outer join food on food.stored_in = food_storage.name and not food.expired;
nombre nombre
cajón bolsas de té
gabinete arroz
gabinete harina
refrigerador (nulo)

Sin embargo, estoy tratando de realizar esta consulta usando JPA y hacer que el resultado se asigne con éxito a las entidades JPA. Modelé mis entidades JPA así:

 @Entity @Table(name = "food_storage") @Data public class FoodStorage { @Id private String name; @OneToMany(mappedBy = "stored_in") private List<Food> foodContents; } @Entity @Table(name = "food") @Data public class Food { @Id private String name; @Column private boolean expired; @Column(name = "stored_in") private String storedIn; }

Para el resultado de la consulta SQL sin procesar anterior, necesito que el resultado se vuelva a asignar a entidades como esta:

 [ FoodStorage(name=drawer, foodContents=[ Food(name=teabags, expired=false, storedIn=drawer) ]), FoodStorage(name=fridge, foodContents=[]), FoodStorage(name=cabinet, foodContents=[ Food(name=rice, expired=false, storedIn=cabinet), Food(name=flour, expired=false, storedIn=cabinet) ]) ]

Intenté usar este código:

 String sql = """ select food_storage.*, food.* from food_storage left outer join food on food.stored_in = food_storage.name and not food.expired; """; Query query = entityManager.createNativeQuery(sql, FoodStorage.class); System.out.println(query.getResultList());

Pero este es el resultado que obtengo:

 [ FoodStorage(name=drawer, foodContents=[ Food(name=teabags, expired=false, storedIn=drawer), Food(name=beans, expired=true, storedIn=drawer) ]), FoodStorage(name=fridge, foodContents=[ Food(name=leftovers, expired=true, storedIn=fridge) ]), FoodStorage(name=cabinet, foodContents=[ Food(name=rice, expired=false, storedIn=cabinet), Food(name=flour, expired=false, storedIn=cabinet) ]), FoodStorage(name=cabinet, foodContents=[ Food(name=rice, expired=false, storedIn=cabinet), Food(name=flour, expired=false, storedIn=cabinet) ]) ]

Hibernate parece ignorar mi unión manual y, en su lugar, solo construye una FoodStorage por fila de resultados y, posteriormente, obtiene todos los Food por FoodStorage . ¿Cómo puedo superar este problema?

Encontré la anotación @Where de Hibernate. Desafortunadamente para mi caso del mundo real, el filtro de unión es dinámico, por lo que no puedo usarlo.

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

Una posible solución es usar una "unión de búsqueda" en JQPL en lugar de SQL nativo:

 var query = entityManager.createQuery( """ select distinct fs from FoodStorage fs join fetch fs.foodContents f where f.expired = false """, FoodStorage.class); List<FoodStorage> result = query.getResultList(); System.out.println(result);

lo que resulta en:

 [ FoodStorage(name=cabinet, foodContents=[ Food(name=rice, expired=false, storedIn=cabinet), Food(name=flour, expired=false, storedIn=cabinet) ]), FoodStorage(name=drawer, foodContents=[ Food(name=teabags, expired=false, storedIn=drawer) ]) ]

lo cual creo que se debe a que hibernate es consciente del propósito de la unión y comprende correctamente cómo asignar el resultado a las entidades.

Pero esto tiene algunos inconvenientes:

  • A pesar de la left outer join , no puede obtener FoodStorage con cero Food . El uso de left outer join fetch en lugar de solo join fetch no hace ninguna diferencia. Por lo que entiendo, eso se debe a que la condición del filtro tiene que ser un filtro regular where f.expired = false , ya que JQPL no admite especificarlo como una condición de combinación como left outer join fetch fs.foodContents f on f.expired = false
  • Requiere una select distinct porque, de lo contrario, hibernate duplica la entidad FoodStorage para cada Food que contiene.
  • Las limitaciones de JPQL se aplican, naturalmente.

Especialmente el último punto puede ser un factor decisivo, ya que con frecuencia me encuentro en una situación en la que JPQL no puede expresar lo que necesito expresar en SQL.

over 4 years ago · Santiago Trujillo Relatório

0

String sql = "select distinct food_storage.* from food_storage left outer join food on food.stored_in = food_storage.name and not food.expired; ";

La food.* es inútil. Puede usar spring.jpa.properties.hibernate.show_sql=true para imprimir sql. La devolución food.* no reduce el número de consultas.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda