#jpa #eclipselink
#jpa #eclipselink
Вопрос:
Я постараюсь сформулировать вопрос более просто:
@Entity
public class One implements Serializable {
...
@Id
@GeneratedValue
private Long id;
@OneToMany
@OrderBy("name ASC")
private List<Many> many;
...
Сначала я заполняю список несколькими объектами и сохраняю один объект. Во-вторых, я извлекаю (em.find) единый объект, ожидающий список в порядке возрастания по многим #name, но он не упорядочен по имени. Список упорядочен по идентификатору. При необходимости полный код см. Ниже.
Оригинальное сообщение несколько дней назад:
Я использую текущий пакет Netbeans Glassfish.
Версия продукта: NetBeans IDE 8.0 (сборка 201403101706) Обновления: Среда IDE NetBeans обновлена до версии NetBeans 8.0 Исправление 2 Java: 1.7.0_51; 64-разрядная серверная виртуальная машина Java HotSpot (TM) 24.51-b03 Среда выполнения: Java (TM) SE Среда выполнения 1.7.0_51-b13 Система: Mac OS X версии 10.9.3 работает наx86_64; UTF-8; de_DE (nb)
Аннотация JPA @OrderBy полностью игнорируется.
@Entity
public class One implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
private Long id;
@OneToMany
@OrderBy("name ASC")
private List<Many> many;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<Many> getMany() {
return many;
}
public void setMany(List<Many> many) {
this.many = many;
}
}
Множество объектов
@Entity
public class Many implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
private Long id;
private String name;
public Many() {
}
public Many(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Класс обслуживания (EJB)
@Stateless
public class Service {
@PersistenceContext(unitName = "cwPU")
private EntityManager em;
public One createOne() {
return em.merge(new One());
}
public Many createMany(String name) {
return em.merge(new Many(name));
}
public One add(Long oneId, Long manyId) {
One one = em.find(One.class, oneId);
Many many = em.find(Many.class, manyId);
one.getMany().add(many);
return one;
}
public One find(Long id) {
One one = em.find(One.class, id);
return one;
}
}
Основной класс
public class Main {
public static void main(String[] args) throws NamingException {
EJBContainer container = EJBContainer.createEJBContainer();
Context ctx = container.getContext();
Service service = (Service) ctx.lookup("java:global/classes/Service");
One one = service.createOne();
Many many = service.createMany("the-first");
service.add(one.getId(), many.getId());
many = service.createMany("a-second");
one = service.add(one.getId(), many.getId());
one = service.find(one.getId());
System.out.println("-------------------------------------------------");
for (Many m : one.getMany()) {
System.out.println(m.getName());
}
container.close();
}
}
Вывод:
the-first
a-second
Независимо от того, что я пишу в аннотацию @OrderBy (name ASC, name DESC, id ASC, id DESC), выходные данные всегда имеют одинаковый порядок возрастания по идентификатору.
Есть идеи, чего мне не хватает?
Ответ №1:
@Orderby
Аннотация на самом деле так не работает. Согласно javadoc, аннотация «Определяет порядок элементов коллекции … в момент извлечения коллекции».
Таким образом, аннотация влияет на результат запроса (find), но не определяет порядок в коллекции, в которую вы сохраняете результирующий набор.
Комментарии:
1. Спасибо за комментарий. Но я не понимаю javadoc таким образом. Не могли бы вы привести пример, как получить элементы коллекции? Как я понял, аннотация @OrderBy не применяет какой-либо порядок объектов к базе данных. Но при извлечении они вставляются в коллекцию (список) в указанном порядке. Посмотрите на основной класс в конце. one = service.find(one.getId()); (в основном em.find(One.class , идентификатор);) Итак, я извлекаю сущности.
2. Как указано, JPA извлечет список из базы данных, используя поле orderby, как вы определили. Однако он не поддерживает порядок в вашей сущности, поэтому ваше приложение должно поддерживать этот порядок при добавлении новых элементов. Каждый запрос или вызов поиска не обязательно переходит в базу данных из-за кэширования объектов, поэтому вы должны постоянно поддерживать этот список или ожидать возникновения подобных проблем. Вы можете принудительно перезагрузить список, вызвав em.refresh , но более эффективно просто поддерживать порядок вашей коллекции.
3. Еще раз спасибо. Я думаю, я понимаю ваш комментарий и документы. Но комментарий не относится к моему примеру кода. Пожалуйста, посмотрите на это еще раз. Я вставляю две
Many
сущности во многие отношения сущностиOne
. Затем я сохраняюOne
и извлекаю его снова. Теперь список многих отношений должен быть упорядочен. Но это не так. Вызов обновления не имеет никакого эффекта. Я понятия не имею, что здесь происходит не так или как сузить проблему.
Ответ №2:
Решение заключается в вызове em.refresh (в нужном месте), как указано Крисом и WPrecht. Мне пришлось сделать это в отдельном методе EJB.
Это не сработало:
public One find(Long id) {
em.refresh(em.find(One.class, id)); // did not work
One one = em.find(One.class, id);
return one;
}
Добавление отдельного метода обновления
public void refresh(Long id) {
em.refresh(em.find(One.class, id));
}
и вызов его в основной программе
...
service.refresh(one.getId());
one = service.find(one.getId());
...
работает!
Вероятно, мне нужно больше читать, чтобы понять кеширование.
Комментарии:
1. Я использую EclipseLink 2.6.0. em.refresh(entity) тоже выполняет эту работу за меня (em.find(class, id) было недостаточно для применения порядка) — спасибо за подсказку.