Не удается найти вложенный список объектов с помощью Spring Data JPA - PullRequest
0 голосов
/ 24 февраля 2020

У меня проблемы с запросом вложенного списка объектов с помощью Spring Data JPA.

Вот мои сущности:

public class Shipment {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(updatable = false, nullable = false)
   private Long id;

   @CreationTimestamp
   @Column(updatable = false)
   private Date createdAt;

   @UpdateTimestamp
   private Date updatedAt;

   private String orderId;
   private String deliveryId;

   @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
   @JoinColumn(name = "shipment")
   private List<Packet> packets;

   // constructors, getters, setters omitted
}

и вложенный список:

@Entity
public class Packet {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(updatable = false, nullable = false)
   private Long id;

   @CreationTimestamp
   @Column(updatable = false)
   private Date createdAt;

   @UpdateTimestamp
   private Date updatedAt;

   private String packetId;
   @Enumerated(EnumType.STRING)
   private PacketType packetType;
}

Тогда у меня есть простая конечная точка отдыха:

@GetMapping(path = "/shipments", produces = "application/json")
    public List<ShippingIds> getShipments(SearchCriteria searchCriteria) {
    List<Shipment> shipments = shipmentService.getShipmentIds(searchCriteria);
    return buildShipmentIds(shipments);
}

И я использую SearchCriteria в качестве queryParams (/shipments?packetId={packetId}&orderId={orderId}&deliveryId={deliveryId}...

И мой Сервис, где я использую query by example:

public List<Shipment> getShipmentIds(SearchCriteria searchCriteria) {
    Shipment shipment = Shipment.builder()
            .orderId(searchCriteria.getOrderId())
            .deliveryId(searchCriteria.getDeliveryId())
            .packetId(searchCriteria.getPacketId())
            .build();

    // My problem is here - How do I do get the associated Shipment object if my search criteria is a packetId? 
    if (searchCriteria.getPacketId()!= null) {
        return shipmentRepository.findByPackets_Packets_packetId(searchCriteria.getPacketId());
    } else {
        Example<Shipment> example = Example.of(shipment);
        return shipmentRepository.findAll(example);
    }
}

И мой репозиторий:

@Repository
public interface ShipmentRepository extends JpaRepository<Shipment, Long> {

    List<Shipment> findByPackets_Packets_packetId(String packetId);

}

Поскольку мой объект Shipment имеет список Packet, я не могу просто включить его в Example, или, по крайней мере, я не знаю как.

Но я должен иметь возможность извлечь соответствующую отправку на основе одной строки packetId, верно?

Я получаю исключение:

Вызвано: org.springframework.data.mapping.PropertyReferenceException: Не найдено ни одного участка свойств для типа Packet! Вы имели в виду 'packageId'? определить запрос самостоятельно:

@Query("select s from Shipment s left join s.packets p where s.id = p.shipment")

Но тогда я получаю:

Вызывается: org.hibernate.QueryExcept ion: не удалось разрешить свойство: отгрузка: com.shipment.persistence.model.Packet

Хотя пересылка является моим внешним ключом.

Есть идеи, что я делаю не так? Или что я могу улучшить?

1 Ответ

2 голосов
/ 24 февраля 2020

Вы находитесь в правильном направлении, но есть некоторые ошибки.

Во-первых, ошибка

Причина: org.hibernate.QueryException: не удалось разрешить свойство: отгрузка of: com.shipment.persistence.model.Packet

сообщает, что отгрузка не является полем, которое вы определили в классе Packet, и, следовательно, дает сбой. Неважно, что на стороне базы данных он у вас есть, если вы хотите выполнить запрос с использованием этого поля, он должен отображаться на стороне класса.

Сказав это, нет необходимости добавлять его в ваш класс для достижения вашего первоначального намерения, а именно для запроса всех отправлений, которые имеют пакет с определенным идентификатором. Причина в том, что в этом нет необходимости, состоит в том, что вы уже сопоставили отношение на стороне объекта отгрузки, поэтому нет необходимости снова сопоставлять его с объектом Packet. Это может потребоваться в другом сценарии ios, но не в вашем.

Вы были правы, добавив аннотацию @Query поверх вашего метода репозитория. Однако в нем отсутствует самая важная часть - получение посылок с указанным идентификатором пакета. Кроме того, предоставленное вами условие соединения не является обязательным и может быть опущено, поскольку Hibernate позаботится об этом на основе сопоставления, помеченного как @JoinColumn (name = "shipment").

Your @ Аннотация запроса должна выглядеть следующим образом:

@Query("from Shipment s join s.packets p where p.packetId = :packetId")

Объяснение:

  1. Пропущена часть 'Select s', она является избыточной при выборе всех полей.
  2. удалено левое соединение и заменено соединением, так как нет необходимости выбирать объекты отгрузки, которые не соответствуют критериям. Внутреннего соединения достаточно, чтобы hibernate подготовил условие для связанных объектов.
  3. Добавлено условие, которое приведет к отправкам, в которых есть пакет, соответствующий идентификатору данного пакета.

Это будет выдает следующий запрос, сгенерированный Hibernate:

SELECT
    shipment0_.id AS id1_1_0_,
    packets1_.id AS id1_0_1_,
    packets1_.packet_id AS packet_i2_0_1_,
 // and the rest of the fields of both objects
FROM
    shipment shipment0_
INNER JOIN packet packets1_ ON
    shipment0_.id = packets1_.shipment
WHERE
    packets1_.packet_id =?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...