EntityManager пытается вставить сущности без запроса - PullRequest
1 голос
/ 10 ноября 2011

Возможно, я слишком упрощаю это, предоставив вам лишь небольшой фрагмент кода (и я опубликую больше, если это так), но я думаю, что сначала меньше, тем лучше:

Iиметь сущность типа Asset, которая имеет поле типа Location, которое также является сущностью.Когда я устанавливаю Местоположение Актива, я также должен установить Местоположение его дочерних элементов.

Location location = asset.getLocation();
em.merge(location);
em.flush();

childAsset.setLocation(asset.getLocation());
em.flush();

Когда я запускаю flush (), я получаю следующее исключение:

ВнутреннийИсключение: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: уникальное ограничение (SWRADMIN.LOCATION_PK) нарушено

Мой вопрос ... почему этот объект Location даже пытается сохраниться?Все, что я делаю, это устанавливаю переменную в сущности.

Раньше это работало нормально, но мы просто переключились на использование Eclipselink и Java EE 6, и эта проблема всплыла.

Решение?Я использовал идею «отсоединения» снизу и сделал следующее изменение:

Location location = asset.getLocation();

em.detach(childAsset);
childAsset.setLocation(asset.getLocation());
em.merge();
em.flush();

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

Ответы [ 3 ]

2 голосов
/ 10 ноября 2011

Если объект находится в управляемом состоянии, то диспетчер сущностей синхронизирует его с базовой базой данных, сохраняя объект неявно (вероятно, в конце транзакции) или явно, когда вы вызываете метод em.flush().

Вы можете использовать em.detach(entity) для отсоединения одного объекта или em.clear() для отсоединения всех объектов. Тогда изменения, внесенные в сущность / сущности, не будут отражены в базе данных.

Чтобы лучше справиться с этим, вы можете использовать BMT (Bean Managed Transaction), где вам нужно обрабатывать персистентность сущности, транзакцию вручную.

Редактировать:

Location location = asset.getLocation();
childAsset.setLocation(location);
em.merge(childAsset);
em.flush();
0 голосов
/ 11 ноября 2011

Из кода похоже, что вы используете неуправляемую версию местоположения и связываете ее с ChildAsset. Если ваше отношение childAsset-> Location помечено как каскадное сохранение, то спецификация, требующая наличия perist, будет вызываться для Location при сбросе или фиксации. Поскольку Location не является управляемым объектом, он требует исключения при сохранении.

Когда управление местоположением осуществляется (например, когда вы вызываете слияние для ChildAsset или если вы использовали управляемый экземпляр Location, возвращенный из em.merge (местоположение); вызов), операция persist для ChildAsset-> Location не работает.

Не связывайте неуправляемые объекты с отношениями, помеченными как сохраненные каскадом.

0 голосов
/ 10 ноября 2011

Итак, местоположение - это существующее местоположение или новый объект?

Как это было прочитано, было ли оно прочитано из другой транзакции или менеджера сущностей или каким-то образом отсоединено?Если это так, то вам нужно перечитать (найти) или объединить его.

Если он новый и относится к управляемому объекту, тогда да, flush должен записать его.

...