В жизни я не могу понять, как построить этот запрос JPA.
Мне нужно найти TransactionLogs, которые не были переданы в данном SyncSendingConfig , упорядочены по идентификатору.
Исследуя его на SO, я полагаю, что в SQL должно быть возможно выполнить внешнее соединение, где идентификаторы равны нулю для одной стороны, как на этой диаграмме:
Вот сущности, с которыми мне приходится работать.
@Entity
public class SyncSendingConfig {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "sendingConfig")
private Set<SyncJob> sendJobs = new HashSet<>();
}
@Entity
public class SyncJob {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "sending_config_id")
private SyncSendingConfig sendingConfig;
@ManyToMany(cascade = { CascadeType.ALL })
@JoinTable(
name = "SyncJob_TransactionLog",
joinColumns = { @JoinColumn(name = "sync_job_id") },
inverseJoinColumns = { @JoinColumn(name = "transaction_log_id") }
)
private Set<TransactionLog> transmitted = new HashSet<>();
}
@Entity
public class TransactionLog {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@ManyToMany(mappedBy = "transmitted")
private Set<SyncJob> syncJobs = new HashSet<>();
}
И DAO, которую я пытаюсь написать:
public interface SyncSendingConfigDao extends JpaRepository<SyncSendingConfig, Long> {
// TODO: This is the query I'm trying to get to work
/** Returns those transactions that were never sent for the given SyncSenderConfig, ordered by ID */
@Query("SELECT tl FROM SyncJob sj "+
"JOIN SyncSendingConfig ssc ON sj.sendingConfig = ssc.id AND ssc.id= :sendingConfigId "+
"RIGHT JOIN TransactionLog tl on tl.syncJobs = sj "+
"WHERE sj.id is null"
)
Stream<TransactionLog> findTransactionsNotSentForSyncSendingConfigId(@Param("sendingConfigId") long sendingConfigId);
// If this part is relevant, this join shows how I can get only those SyncJobs which are related to the SyncSendingConfig of interest
@Query("SELECT sj FROM SyncJob sj JOIN SyncSendingConfig ssc ON sj.sendingConfig = ssc.id WHERE ssc.id= :sendingConfigId ")
@QueryHints(value = @QueryHint(name = org.hibernate.jpa.QueryHints.HINT_FETCH_SIZE, value = "500"))
Stream<SyncJob> findJobs(@Param("sendingConfigId") long sendingConfigId);
}
Запрос выше по DAO показывает, что я пытаюсь сделать. Я действительно не уверен, как перевести SQL в JPQL ... особенно в отношении условий и порядка соединения.
Обновление:
Вот точный запрос SQL, который я пытаюсь перевести. Это соответствует всем отношениям, определенным hibernate в классах выше.
select tl.*
from sync_job sj
join sync_sending_config ssc
on ssc.id = sj.sending_config_id and ssc.id=2
join sync_job_transaction_log sjtl
on sjtl.sync_job_id = sj.id
RIGHT JOIN transaction_log tl
on tl.id = sjtl.transaction_log_id
where sjtl.sync_job_id is null
Когда этот запрос выполняется напрямую, он возвращает точные результаты поиска.
Если кто-то может предложить помощь, я был бы очень признателен. Я бежал к стене, пытаясь понять синтаксис JPQL.
Спасибо
Обновление 2
После работы с @S B ', похоже, что JPQL не поддерживает правильное соединение. Если не считать, как написать это в JPQL с левым соединением (если возможно), я пошел с собственным запросом:
@Query(value = "select tl.* from sync_job sj "+
"join sync_sending_config ssc on ssc.id = sj.sending_config_id and ssc.id = :sendingConfigId "+
"join sync_job_transaction_log sjtl on sjtl.sync_job_id = sj.id "+
"RIGHT JOIN transaction_log tl on tl.id = sjtl.transaction_log_id "+
"where sjtl.sync_job_id is null",
nativeQuery = true)
@QueryHints(value = @QueryHint(name = org.hibernate.jpa.QueryHints.HINT_FETCH_SIZE, value = "500"))
Stream<TransactionLog> findTransactionsNotSentForSyncSendingConfigId(@Param("sendingConfigId") long sendingConfigId);