#hibernate #spring-data-jpa #spring-repositories
#спящий режим #spring-data-jpa #spring-репозитории
Вопрос:
У меня есть объект события, который выглядит следующим образом. Каждое событие может иметь список EventDetails, который также показан ниже. (Я максимально упростил эти объекты для объяснения)
@Entity(name = "event")
data class Event(
@Id
@GeneratedValue
@Type(type = "uuid-char")
val id: UUID = UUID.randomUUID(),
@OneToMany(
cascade = [CascadeType.ALL],
orphanRemoval = true
)
@JoinColumn(
name = "event_id",
nullable = false
)
val eventDetails: List<EventDetails>
)
@Entity(name = "event_details")
data class EventDetails(
@Id
@GeneratedValue
@Type(type = "uuid-char")
val id: UUID = UUID.randomUUID(),
val type: String
)
У меня есть запрос, в котором я хочу вернуть все события, которые содержат сведения определенных типов, но более того, для каждого события я хочу возвращать только список сведений с предоставленными типами — в этом случае hibernate возвращает полный список, который мне не нужен.
Поэтому я в основном хочу вернуть частичный список сведений о событиях на основе того, что передается в запрос, но полный список объектов возвращается каждый раз. По-видимому, это связано с тем, что hibernate извлекает события, соответствующие запросу, и впоследствии выполняет быструю / отложенную выборку всех EventDetails в зависимости от того, что я установил, не принимая во внимание, что запрос не хотел возвращать все значения списка.
Вот запрос, который выявил проблему —
@Repository
interface EventRepository : CrudRepository<Event, UUID> {
@Query(
"""
select e.* from event e
join event_details ed on e.id = ed.event_id
where ed.type in :types
""", nativeQuery = true
)
fun findEventsByDetails(
@Param("types") types: List<String>
): List<AwardEvent>
}
Вот пример, подчеркивающий проблему. если у меня есть событие как таковое —
Event(eventDetails = listOf(EventDetails(type = "TEST"), EventDetails("OTHER")))
и я запускаю следующую команду —
eventRepository.findEventsByDetails(listOf("TEST"))
затем он должен вернуть список одного события —
Event(eventDetails = listOf(EventDetails(type = "TEST")))
без подробностей, включая тип «OTHER_TEST»
Если у кого-нибудь есть какие-либо идеи, это было бы очень ценно
Ответ №1:
Вот как это работает. В вашем конкретном случае коллекция загружается с задержкой, т.Е. Ваше соединение не имеет значения. В общем, сущности всегда отражают состояние базы данных по мере их отображения. Если вы отфильтровываете элементы из коллекции, это может привести к удалению элементов, которые вы, вероятно, не хотите. Решение этой проблемы заключается в использовании DTO.
Я думаю, что это идеальный вариант использования для представлений объектов Blaze-Persistence.
Я создал библиотеку, позволяющую легко сопоставлять модели JPA с моделями, определяемыми пользовательским интерфейсом или абстрактным классом, что-то вроде весенних прогнозов данных на стероидах. Идея заключается в том, что вы определяете свою целевую структуру (модель домена) так, как вам нравится, и сопоставляете атрибуты (геттеры) с помощью выражений JPQL с моделью сущности.
Модель DTO для вашего варианта использования может выглядеть следующим образом с Blaze-Persistence Entity-Views:
@EntityView(Event.class)
public interface AwardEvent {
@IdMapping
UUID getId();
String getName();
@Mapping("eventDetails[type IN :types]")
Set<EventDetailsDto> getEventDetails();
@EntityView(EventDetails.class)
interface EventDetailsDto {
@IdMapping
UUID getId();
String getType();
}
}
Запрос — это вопрос применения представления сущности к запросу, простейшим из которых является просто запрос по идентификатору.
AwardEvent a = entityViewManager.find(entityManager, AwardEvent.class, id);
Интеграция данных Spring позволяет использовать его почти как проекции данных Spring: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
@Repository
interface EventRepository : CrudRepository<Event, UUID> {
fun findAllEvents(
@OptionalParam("types") types: List<String>
): List<AwardEvent>
}