моя проблема с отсоединенной сущностью, переданной для сохранения.
org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: User; nested exception is
org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: User; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: User
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:280)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:225)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy151.findAllBySalesPointIdIn(Unknown Source)
at OrganizationResolver.getOrganizationsFromDataBase(OrganizationResolver.java:124)
at OrganizationResolver.persistOrganizations(OrganizationResolver.java:89)
at com.inteca.bnmt.ldap.resolver.OrganizationResolver$$FastClassBySpringCGLIB$$3125662c.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
База данных Oracle:
Если создание новой схемы очистки успешно выполнено только один раз, проблема все еще появляется,в UserRepository и OrganizationRepository я использую @EntityGraph, чтобы стремиться.
Entity:
User.class
@MappedSuperclass
abstract public class AbstractUser extends AbstractEntity {
@Basic(optional = true)
@Column(name = "cn")
private String cn;
@ManyToMany(cascade = {
CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}
, fetch = FetchType.LAZY)
@JoinTable(name = "User_organization", joinColumns = @JoinColumn(name = "UserId")
, inverseJoinColumns = @JoinColumn(name = "organizationId")
)
private java.util.Set<Organization> organization = new java.util.HashSet<Organization>(); }
Organization.class
@MappedSuperclass
abstract public class AbstractOrganization extends AbstractEntity {
@ManyToMany(cascade = {
CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}
, mappedBy = "organization", targetEntity = User.class, fetch = FetchType.LAZY)
private java.util.Set<User> user = new java.util.HashSet<User>();
}
Мой окончательный код:
UserService.class
@Transactional
public User createUpdate(User user, LdapUser ldapUser) {
log.info("START - createUpdateUser");
/* Resolve dnAdGroups */
user = adGroupResolver.adGroupsResolver(user, ldapUser);
/* Resolve functionalRoles and persist */
user = functionalRoleResolver.functionalRolesResolver(user);
/* Resolve organization and persist */
user = organizationResolver.persistOrganization(user); **<---- inside**
/* Persist primary and User.Organization */
user = organizationUResolver.checkPrimaryOrganization(user);
/* OperatorId addition sequence */
if ((user.getOperatorId() == 0)) {
user.setOperatorId(setNewOperatorId(user));
}
log.info("Trying to save user {} in DB", user);
user = userRepository.saveAndFlush(user);
log.info("User {} updated successfully!", user);
return user;
}
OrganizationResolver.class
@Transactional
public User persistOrganization(User user) {
Set<String> strings = ResolveUtils.cutLdapDnAdGroupsToGetSalesPointId(user, workplaceDn);
Set<Organization> organizationFromDataBase = getOrganizationsFromDataBase(user.getDataSource(), strings); **<---- inside**
if (organizationsFromDataBase.containsAll(user.getOrganization()) && user.getOrganization().containsAll(organizationsFromDataBase))
return user;
/* 1. remove from user.organizations NOT match organizationsFromDataBase */
Set<String> collectSalesPointId = organizationsFromDataBase.stream()
.map(AbstractOrganization::getSalesPointId)
.collect(Collectors.toSet());
Set<Organization> collect = user.getOrganization().stream()
.filter(organization -> !(collectSalesPointId.contains(organization.getSalesPointId())))
.collect(Collectors.toSet());
user.getOrganization().removeAll(collect);
/* 2. remove from organizationsFromDataBase ALL EXISTING in user.organizations */
Set<String> collectName1 = user.getOrganization().stream()
.map(AbstractOrganization::getSalesPointId)
.collect(Collectors.toSet());
Set<Organization> collectExistingInUser = organizationsFromDataBase.stream()
.filter(organization -> collectName1.contains(organization.getSalesPointId()))
.collect(Collectors.toSet());
organizationsFromDataBase.removeAll(collectExistingInUser);
/* 3. add ALL from organizationsFromDataBase to user.organizations */
user.getOrganization().addAll(organizationsFromDataBase);
return user;
}
Set<Organization> getOrganizationsFromDataBase(String dataSource, Set<String> organizationIds) {
Set<Organization> foundOrganizations = new HashSet<>();
if (organizationIds.isEmpty()) return foundOrganization;
foundOrganizations = organizationRepository.findAllBySalesPointIdIn(organizationIds); **<---- detach error !!!!!**
if (!foundOrganizations.isEmpty())
log.info("Organizations {} found successfully", foundOrganizations.size());
else
log.info("Organizations not found");
return foundOrganizations;
}
Спасибо за любую помощь.