#java #jpa #jpql
#java #jpa #jpql
Вопрос:
У меня есть отношение @ManyToMany между классом A и классом B: класс A ссылается на коллекцию экземпляров класса B, и это отношение настроено как CascadeType.ALL. Поэтому, когда A A сохраняется в диспетчере сущностей, экземпляры B, на которые ссылается A, также сохраняются.
Оба A и B имеют идентификатор, объявленный с помощью GenerationType .Стратегия идентификации для использования auto_inc из базы данных MySQL.
Проблема заключается в :
- Я создаю новый
- Я загружаю некоторые существующие объекты B из EntityManager с помощью JPQL
- Я добавляю объекты B в коллекцию Bs
=> JPA пытается сохранить объекты B, хотя они уже сохранены (они только что были загружены).
Я не понимаю, почему он пытается сохранить их снова, они были правильно загружены, и их автоматически сгенерированный идентификатор также был хорошо загружен.
Объявление ManyToMany :
@ManyToMany(cascade={CascadeType.ALL})
@JoinTable(name = "ENTRY_ENTITIES", joinColumns =
@JoinColumn(name = "ENTRY", referencedColumnName = "ID"),
inverseJoinColumns = @JoinColumn(name = "ENTITY", referencedColumnName = "ID"))
private List<Entity> entities;
Запрос для загрузки существующих объектов из базы данных :
T result = (T) entityManager.createQuery("SELECT x FROM " entityName " x WHERE x.externalId='" externalId "'").getSingleResult();
Сохраняющийся :
UserTransaction transaction = getTransaction();
try {
transaction.begin();
entityManager.persist(entity);
transaction.commit();
} catch (Throwable t) {
Logger.getLogger(JpaDao.class.getName()).log(Level.SEVERE, null, t);
}
Большое спасибо за вашу помощь!
Комментарии:
1. Покажите нам код объектов, их сопоставление и код, обеспечивающий сохранение. Сообщите нам, какой движок JPA вы используете. Обратите внимание, что cacscade ALL на ManyToMany неверен: вы не хотите, чтобы все Bs A были удалены при удалении A, поскольку на Bs ссылаются другие As .
Ответ №1:
Я не совсем уверен, что это является причиной вашей проблемы, но вы должны включить все это в транзакцию. Не только часть сохранения:
start transaction
load B from DB
create new A
add B to A
commit transaction
Как я уже говорил в своих комментариях, у вас есть другие проблемы с дизайном и кодированием:
- CascadeType .ВСЕ неправильно в ассоциации ManyToXxx. Вы не хотите, чтобы все Bs A были удалены при удалении A, поскольку на эти Bs ссылаются другие As. Это приведет к нарушению ограничений (в лучшем случае) или к несовместимости базы данных (в худшем случае, если у вас не определено ограничение)
- Не используйте конкатенацию строк в своих запросах. Используйте параметризованные запросы. Это позволит избежать проблем с цитированием и атак с использованием инъекций:
SELECT x FROM A x WHERE x.externalId = :externalId
Комментарии:
1. Спасибо, к сожалению, я не могу поместить загрузку и сохранение в одну и ту же транзакцию, потому что сначала я загружаю Bs, затем отображаю их на странице JSF, а затем, когда пользователь отправляет форму, я создаю A и сохраняю ее. Так что это не в том же http-запросе. Или я должен загрузить их снова во второй раз?
2. Нет, вам не нужно их перезагружать. Какой движок JPA вы используете? Является ли ассоциация двунаправленной? Покажите нам полный код обоих объектов и код, используемый для их связывания.
Ответ №2:
Эти объекты B могут быть частью другого контекста сохранения в момент времени, когда вы добавляете их в A. Пробовали ли вы использовать операцию слияния для объектов B после запуска транзакции, прежде чем добавлять их в свой объект A.