В нашем приложении 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 запросов.