JPA сохраняет уже сохраненные объекты из отношений ManyToMany - PullRequest
0 голосов
/ 01 октября 2011

У меня есть отношение @ManyToMany между классом A и классом B: класс A ссылается на коллекцию экземпляров класса B, и это отношение настраивается как CascadeType.ALL. Поэтому, когда A сохраняется с менеджером сущностей, экземпляры B, на которые ссылается A, также сохраняются.

И A, и B имеют идентификатор, объявленный стратегией GenerationType.IDENTITY для использования auto_inc из базы данных MySQL.

Проблема:

  1. Я создаю новый A
  2. Я загружаю некоторые существующие объекты B из entityManager, используя JPQL
  3. Я добавляю объекты 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);
}

Большое спасибо за вашу помощь!

Ответы [ 2 ]

2 голосов
/ 01 октября 2011

Я не совсем уверен, что это является причиной вашей проблемы, но вы должны включить все это в транзакцию. Не только постоянная часть:

start transaction
load B from DB
create new A
add B to A
commit transaction

Как я уже говорил в моих комментариях, у вас есть другие проблемы с дизайном и кодированием:

  • CascadeType.ALL неверен в ассоциации ManyToXxx. Вы не хотите, чтобы все Bs A удалялись при удалении A, поскольку на эти B ссылаются другие As. Это приведет к нарушениям ограничений (в лучшем случае) или к несовместимости базы данных (в худшем случае, если ограничение не определено)
  • Не используйте конкатенацию строк в своих запросах. Используйте параметризованные запросы. Это позволит избежать проблем с цитированием и инъекционных атак: SELECT x FROM A x WHERE x.externalId = :externalId
1 голос
/ 01 октября 2011

Эти сущности B могут быть частью другого персистентного контекста в тот момент, когда вы добавляете их в A. Пробовали ли вы использовать операцию объединения на сущностях B после запуска транзакции, до добавление их к вашей сущности А.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...