#java #hibernate #eclipselink
#java #спящий режим #eclipselink
Вопрос:
У меня есть две сущности Role и Grant со следующим сопоставлением:
public class Role extends BaseBean {
private static final long serialVersionUID = 1L;
private String name;
private Set<Grant> grants = new HashSet<Grant>();
// get set
}
public class Grant implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String data;
}
отображение orm:
<entity name="q2role" class="tn.waycon.alquasar2.adm.model.Role">
<attributes>
<basic name="name">
<column length="800" nullable="false" unique="true"/>
</basic>
<many-to-many name="grants" fetch="EAGER">
<join-table name="role_grant">
<join-column name="role_id"/>
<inverse-join-column name="grant_id"/>
</join-table>
<cascade>
<cascade-all/>
</cascade>
</many-to-many>
</attributes>
</entity>
<entity name="q2grant" class="tn.waycon.alquasar2.adm.model.Grant">
<attributes>
<id name="id">
<column name="id_g"/>
<generated-value stategy="IDENTITY" generator="SEQ_GEN"/>
</id>
<basic name="data"></basic>
</attributes>
</entity>
Теперь, когда я пытаюсь вставить новую роль, содержащую существующие гранты, транзакция завершится неудачно, потому что eclipselink пытается вставить уже существующие гранты. Почему eclipselink ведет себя так странно? Я устанавливаю cascade-all, и eclipselink должен быть достаточно умен, чтобы разделять каскадное сохранение и каскадное слияние.
Main {
Role role = new Role();
List<Grant> grants = grantRepository.getGrantsBydata(List<String> datas);
role.setGrants(grants);
roleRepository.save(role);
}
Журнал:
ПРЕДУПРЕЖДЕНИЕ [http-nio-8080-exec-2] org.springframework.remoting.support.RemoteInvocationTraceInterceptor.invoke Обработка удаленного вызова HttpInvokerServiceExporter привела к фатальному исключению tn.waycon.alquasar2.adm.service.api.IAdminService.createRole org.springframework.transaction.Исключение TransactionSystemException: не удалось зафиксировать JPA транзакции; вложенным исключением является javax.persistence.Исключение RollbackException: Исключение [EclipseLink-4002] (службы сохранения Eclipse — 2.5.2.v20140319-9ad6abd) org.eclipse.persistence.exceptions.Исключение DatabaseException Внутреннее исключение: java.sql.BatchUpdateException: нарушение ПЕРВИЧНОГО КЛЮЧА «PK__Q2GRANT__9DB7D2FA15DA3E5D». Не удается вставить дубликат ключа в object ‘dbo.Q2GRANT «. дублирующее значение ключа (13969). Код ошибки: 2627
Комментарии:
1. Ваш метод сохранения использует слияние или сохраняется?
2. Я использую spring data jpa, в интерфейсе JpaRepository есть только один метод сохранения, в зависимости от того, является первичный ключ нулевым или нет, он решит использовать слияние или сохранение.
Ответ №1:
Вызов Persist заставляет JPA вставлять корневую сущность, но он также каскадирует вызов persist по отношению, отмеченному типом cascade persist . Это косвенно означает, что вы вызываете persist для своего отдельного объекта, который спецификация JPA требует, чтобы поставщики создавали исключение либо немедленно, либо когда транзакция синхронизируется с базой данных (оператор insert).
Параметры Persist и cascade persist предназначены только для использования, когда вы собираетесь вставлять новый граф объектов, поэтому вам может потребоваться пересмотреть, где вы вставляете параметр cascade persist — это имеет последствия.
Параметры
- Чтение существующих объектов перед добавлением их в новый объект и использованием управляемого экземпляра. Поскольку сохранение в управляемом объекте не выполняется, это решит вашу проблему.
- Вместо этого используйте слияние. Слияние позволяет поставщику просматривать экземпляр объекта, чтобы решить, является ли он новым или обновленным, и это каскадируется в график, как указано. Затем Merge возьмет ваш отдельный объект и обработает его соответствующим образом, обновив его.
Ответ №2:
Вы должны удалить, поскольку гранты управляются отдельно от ролей. Использование означает, что при вставке роли все ее права доступа также вставляются, а при ее удалении права доступа также удаляются. В вашем случае я вижу, что гранты уже существуют при создании роли, поэтому вы не захотите, чтобы они, например, были удалены, когда эта роль будет удалена!