JPA Критерии: понижать корень до нескольких подклассов сущностей и фильтровать по одному и тому же естественному идентификатору связанной сущности - PullRequest
0 голосов
/ 05 марта 2019

Учитывая, что у меня есть 4 таблицы:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class SourceEvent {
    @Id
    private Long id;
}

@Entity
@PrimaryKeyJoinColumn(name = "SOURCE_EVENT_ID")
public class PrimaryEvent extends SourceEvent {
    @ManyToOne
    private Account account;
}

@Entity
@PrimaryKeyJoinColumn(name = "SOURCE_EVENT_ID")
public class SecondaryEvent extends SourceEvent {
    @ManyToOne
    private Account account;
}

@Entity
public class Account {
    @Id
    private Long id;

    @NaturalId
    @Column(name = "ACCOUNT_NUMBER", unique = true, nullable = false)
    private long accountNumber;
}

Как видите, SourceEvent является родителем PrimaryEvent и SecondaryEvent, и оба события указывают на Account.

Я бы хотел отфильтровать SourceEvent s по номеру счета Account, используя API критериев JPA.

Я собрал это:

final class Filter {

    private Long accountNumber;

    Specification<SourceEvent> toSpecification() {
        return (Root<SourceEvent> root, CriteriaQuery query, CriteriaBuilder cb) -> {
            return cb.or(
                    cb.equal(cb.treat(root, PrimaryEvent.class).get("account").get("accountNumber"), accountNumber),
                    cb.equal(cb.treat(root, SecondaryEvent.class).get("account").get("accountNumber"), accountNumber)
            );
        };
    }       
}       

, где я использую treat оператор понижается с SourceEvent до PrimaryEvent и SecondaryEvent, и я ставлю оба равных Predicate с cb.or(...)

Когда я звоню sourceEventRepository.findAll(filter.toSpecification()), тогда как sourceEventRepository:

public interface SourceEventRepository extends JpaSpecificationExecutor<SourceEvent>, JpaRepository<SourceEvent, Long> {}

тогда я получаю следующий SQL, сгенерированный Hibernate:

...
from
    source_event sourceeven0_ 
inner join
    primary_event sourceeven0_1_ 
        on sourceeven0_.id=sourceeven0_1_.source_event_id 
inner join
    secondary_event sourceeven0_2_ 
        on sourceeven0_.id=sourceeven0_2_.source_event_id 
cross join
    account account1_ 
where
    sourceeven0_1_.account_id=account1_.id 
    and (
        account1_.account_number=123 
        or account1_.account_number=123
    )

, что не работает для меня, потому что оно не включает SecondaryEvent s с данным номером счета.

Как заставить это работать?

...