Hibernate: BigInteger против Long из собственного запроса, который будет использоваться в запросе JPQL - PullRequest
0 голосов
/ 09 сентября 2018

В нашем приложении Java EE EJB у нас есть следующее отображение JPA / Hibernate класса:

@Entity
@Table(name="T")
@TableGenerator( /* all annotation attributes */)
public class T {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    @Column(name="SEQ_T", nullable = false)
    private long seqT;

    @OneToMany(
        cascade = CascadeType.ALL, 
        orphanRemoval = true,
        mappedBy = "t",
        fetch = FetchType.LAZY
    )
    private List<W> wu;

}

и это классы, связанные с ним:

@Entity
@Table(name="W")
@TableGenerator( /* all annotation attributes */)
public class W {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    @Column(name="SEQ_W", nullable = false)
    private long seqW;

    @Column(name="SEQ_T", nullable = false)
    private long seqT;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "SEQ_T", insertable = false, updatable = false)
    private T t;

    @OneToMany(
        cascade = CascadeType.ALL, 
        orphanRemoval = true,
        mappedBy = "w",
        fetch = FetchType.LAZY
    )
    private List<WA> wua;
 }

@Entity
@Table(name="WA")
@TableGenerator( /* all annotation attributes */)
public class WA {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    @Column(name="SEQ_W_A", nullable = false)
    private long seqWA;

    @Column(name="SEQ_W", nullable = false)
    private long seqW;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "SEQ_W", insertable = false, updatable = false)
    private W w;

}

Более того, у нас есть запланированное задание, которое периодически выполняется TimerService EJB. Прежде всего, это задание должно понимать, есть ли что-то для выполнения, поэтому оно выполняет собственный SQL-запрос , подобный следующему, чтобы восстановить список pk из таблицы T в соответствии с несколькими условиями:

List<Long> seqTs = (List<Long>)em.createNativeQuery("select SEQ_T from T").getResultList();

, где em - это экземпляр EntityManager. Запрос, очевидно, не так прост, но очень сложен, так как он получается из некоторых JOIN и подзапросов с другими таблицами. Если возвращенный список не пустой, то задание может выполнять свою работу, и этот JPQL выполняется для загрузки сущностей, которыми он манипулирует:

String queryJPQL = "select wu from W wu JOIN FECTCH wu.wua where wu.seqT in :seqTs";
List<Workup> wus = em.createQuery(queryJPQL, W.class)
                     .setParameter("seqTs", seqTs)
                     .getResultList();

Этот запрос выполняется, потому что даже если нам всегда нужны данные в отношении @OneToMany, если мы установим это отношение как EAGER, то будет выполнено N + 1 запрос. Вместо этого с JOIN FETCH выполняется уникальный запрос, восстанавливающий своего рода представление, а затем сущности и отношения связываются с помощью Hibernate.

Ну, проблема в том, что это исключение возникает при вызове .setParameter():

Исключение в потоке "main" java.lang.IllegalArgumentException: элемент значения параметра [1] не соответствует ожидаемому типу [java.lang.Long (n / a)]

Читая много постов здесь и установив точку останова в Eclipse, я обнаружил, что из собственного запроса возвращается не List<Long>, а List<BigInteger> (в соответствии с собственным типом PK в базе данных), без каких-либо ClassCastException или похожие. Почему это? Итак, я думаю, что я должен выполнить что-то вроде этого раньше:

List<Long> seqTLong = new ArrayList<Long>();
for(BigInteger seqNative : seqTs) 
        seqTLong.add(seqNative.longValue());

и передать его на запрос. В любом случае, это правильное решение? Это безопасно? Это потому, что наше приложение поддерживает 3 БД и соответственно построено в 3 JAR ANT: Oracle, PostgreSQL и SQL Server. Могу ли я предположить, что значение PK всегда BigInteger для каждой БД? В Oracle мы используем Number(19), в PostgreSQL мы используем BigInt ... Я не помню о SQL Server. Затем эти объекты передаются в DRools, и когда правила применяются, это задание использует EntityManager для сохранения данных. Вот почему мне нужно, чтобы объекты JPA были загружены, иначе я бы получил

Вызвано: org.hibernate.PersistentObjectException: отсоединенная сущность передана для сохранения

или мне придется снова вызывать .find() для каждого факта, модифицированного DRools, и устанавливать его атрибуты, вызывая геттеры от других. Что по-прежнему вызывает N + 1 запросов.

1 Ответ

0 голосов
/ 10 сентября 2018

Более безопасный метод - использовать Number вместо BigInteger

List<Long> seqTLong = new ArrayList<Long>();
for(Number seqNative : seqTs) {
        seqTLong.add(seqNative.longValue());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...