插入具有单向多对多关系的新实体生成级联持久而不是级联合并
insert new entity that has an unidirectional many-to-many relationship generate cascade-persist instead of cascade-merge
我有两个实体 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 必须足够智能以区分 cascade-persist 和 cascade-merge。
Main {
Role role = new Role();
List<Grant> grants = grantRepository.getGrantsBydata(List<String> datas);
role.setGrants(grants);
roleRepository.save(role);
}
日志:
WARNING [http-nio-8080-exec-2]
org.springframework.remoting.support.RemoteInvocationTraceInterceptor.invoke
Processing of HttpInvokerServiceExporter remote call resulted in fatal
exception tn.waycon.alquasar2.adm.service.api.IAdminService.createRole
org.springframework.transaction.TransactionSystemException: Could
not commit transaction JPA; nested exception is
javax.persistence.RollbackException: Exception [EclipseLink-4002]
(Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd)
org.eclipse.persistence.exceptions.DatabaseException Internal
Exception: java.sql.BatchUpdateException: Violation of PRIMARY KEY
"PK__Q2GRANT__9DB7D2FA15DA3E5D". Can not insert duplicate key in
object 'dbo.Q2GRANT ". duplicate key value (13969). Error Code: 2627
您应该删除 Grants,因为 Grants 与 Roles 分开管理。
Using 表示插入 Role 时,其所有 Grants 也被插入,删除 Role 时,Grants 也被删除。
在你的情况下,我可以看到在创建角色时授权已经存在,所以你不希望在删除角色时删除它们!
调用 Persist 会导致 JPA 插入根实体,但它也会在标有级联持久类型的关系中级联持久调用。这间接意味着您在分离的实体上调用 persist,JPA 规范要求提供者立即或在事务与数据库(插入语句)同步时抛出异常。
Persist 和 cascade persist 选项仅在您要插入新对象图时使用,因此您可能需要重新评估在 cascade persist 选项中放置的位置 - 它会产生后果。
选项是
- 在将现有实体添加到新实体之前读取现有实体
并使用托管实例。因为持久化在托管实体上
是空操作,这将解决您的问题。
- 改为使用合并。合并
允许提供者查看实体实例以决定它是否
是新的还是更新,并且这会按指定级联到图形。
然后 Merge 将获取您的分离实体并处理它
适当地更新它。
我有两个实体 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 必须足够智能以区分 cascade-persist 和 cascade-merge。
Main {
Role role = new Role();
List<Grant> grants = grantRepository.getGrantsBydata(List<String> datas);
role.setGrants(grants);
roleRepository.save(role);
}
日志:
WARNING [http-nio-8080-exec-2] org.springframework.remoting.support.RemoteInvocationTraceInterceptor.invoke Processing of HttpInvokerServiceExporter remote call resulted in fatal exception tn.waycon.alquasar2.adm.service.api.IAdminService.createRole org.springframework.transaction.TransactionSystemException: Could not commit transaction JPA; nested exception is javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd) org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.BatchUpdateException: Violation of PRIMARY KEY "PK__Q2GRANT__9DB7D2FA15DA3E5D". Can not insert duplicate key in object 'dbo.Q2GRANT ". duplicate key value (13969). Error Code: 2627
您应该删除 Grants,因为 Grants 与 Roles 分开管理。 Using 表示插入 Role 时,其所有 Grants 也被插入,删除 Role 时,Grants 也被删除。 在你的情况下,我可以看到在创建角色时授权已经存在,所以你不希望在删除角色时删除它们!
调用 Persist 会导致 JPA 插入根实体,但它也会在标有级联持久类型的关系中级联持久调用。这间接意味着您在分离的实体上调用 persist,JPA 规范要求提供者立即或在事务与数据库(插入语句)同步时抛出异常。
Persist 和 cascade persist 选项仅在您要插入新对象图时使用,因此您可能需要重新评估在 cascade persist 选项中放置的位置 - 它会产生后果。
选项是
- 在将现有实体添加到新实体之前读取现有实体 并使用托管实例。因为持久化在托管实体上 是空操作,这将解决您的问题。
- 改为使用合并。合并 允许提供者查看实体实例以决定它是否 是新的还是更新,并且这会按指定级联到图形。 然后 Merge 将获取您的分离实体并处理它 适当地更新它。