JPA EmbeddedId с @OneToMany - невозможно выполнить запрос с JOIN для работы - PullRequest
0 голосов
/ 19 марта 2019

Мы строим планировщик встреч. У нас много гостей, и каждый может посетить множество событий: сущности «Гость» и «Событие». Это много ко многим с промежуточной сущностью, которая называется "EventGuestRelation". Он имеет @EmbeddedId с двумя столбцами внешнего ключа Integer, который сохраняется хорошо, а встроенные методы JPArepository ведут себя нормально.

Проблема заключается в том, что я запрашиваю репозиторий EventGuestRelation. Я не могу заставить программу вернуть мне EventGuestRelations, которые содержат определенное событие или определенного гостя. Просто ноль. Я показываю запросы на событие здесь для краткости.

Я пробовал

@Query("SELECT r.event FROM EventGuestRelation r WHERE r.event= :event")    
public List<EventEntity> getEventIdsForEvent(@Param(value = "event") EventEntity event); 

и

public List<EventGuestRelation> findByEvent(EventEntity event);

Оба производят SQL:

Hibernate: 
    select
        evententit1_.id as id1_3_,
    ...
    from
        user_event_guest eventguest0_ 
    inner join
        eventlist evententit1_ 
            on eventguest0_.event_sub=evententit1_.id 
    where
        eventguest0_.event_sub=?

Правильный объект:

@Entity
@Table
public class EventEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    ...

    @OneToMany(mappedBy = "event" , cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) 
    @JsonBackReference 
    private Set<EventGuestRelation> subscriptions = new HashSet<>();
    ...

Промежуточный субъект:

@Entity
@Table
public class EventGuestRelation {

    @Embeddable
    public static class EventGuestId implements Serializable {

        @Column(name = "EVENT_ID")
        protected Integer eventId;
        ... 
    }

    @EmbeddedId
    protected EventGuestId id = new EventGuestId();

    @ManyToOne 
    @JoinColumn(name = "event_sub", insertable = false, updatable = false)
    private EventEntity event;
    ...

Левая сущность (Гость) опущена.

Repository:

public interface EventGuestRepository extends JpaRepository<EventGuestRelation, EventGuestId> {

И части метода испытаний:

private final UserEntity ALYSSA = new UserEntity();
private final EventEntity GUESTING = new EventEntity();
private final EventGuestRelation AGUESTING = new EventGuestRelation();
userRepo.save(ALYSSA); // cascades to intemediate entity, checked;
AGUESTING.subscribe(ALYSSA, GUESTING); //bidirectional relation setter

List<EventEntity> eventsII = eventGuestRepo.getEventIdsForEvent(GUESTING);
        assertEquals(eventsII.size(), 1); // fails

Я могу решить эту проблему неоптимальным образом:

   Set<EventGuestRelation> subscriptions = ALYSSA.getSubscriptions();
   Set<EventEntity> events = subscriptions.stream().map(s -> s.getEvent()).collect(Collectors.toSet())

но, очевидно, это не так элегантно, как запрос к базе данных напрямую.

Любая помощь будет высоко ценится. Постскриптум Это та же Алисса из SICP. Некоторые талисманы просто отказываются переходить в безвестность.

Ответы [ 2 ]

0 голосов
/ 03 апреля 2019

Имена столбцов соединения должны совпадать с именами столбцов во встроенном первичном ключе. Я пропустил это. Поэтому у моей промежуточной сущности было 4 столбца в базе данных вместо 2. Это привело к тому, что запрос возвратил нули. После того, как я сделал имена равными, запросы сработали.

Промежуточный объект, исправленный, имеет во встроенном ключе: @Column(name = "GUEST_ID") protected Integer userGuestId;

И в столбце соединения: @ManyToOne @JoinColumn(name = "GUEST_ID", insertable = false, updatable = false) private UserEntity guest;

0 голосов
/ 22 марта 2019

Я никогда не работал с @Embeddable сущностями. Возможно, вы можете использовать что-то полезное в этой статье Spring-Data docs , но в качестве плана резервного копирования я думаю, что вы всегда можете переписать свои запросы, используя собственный SQL.

@Query(value = "SELECT e FROM event_guest_relation AS egr JOIN event AS e ON egr.event_id = e.id WHERE egr.event_id = :eventId", nativeQuery = true)
public List<EventEntity> getEventIdsForEvent(@Param(value = "eventId") Integer eventId);

и

@Query(value = "SELECT egr FROM event AS e JOIN event_guest_relation AS egr ON egr.event_id = e.id WHERE e.id = :eventId", nativeQuery = true)
public List<EventGuestRelation> findByEvent(@Param(value = "eventId") Integer eventId);
...