当我第一次检索必须在 @ManyToMany 关系中使用的对象时,为啥我会获得这个“传递给持久化的分离实体”?

Posted

技术标签:

【中文标题】当我第一次检索必须在 @ManyToMany 关系中使用的对象时,为啥我会获得这个“传递给持久化的分离实体”?【英文标题】:Why am I obtaining this "detached entity passed to persist" when I first retrieve the object that has to be used in a @ManyToMany relationship?当我第一次检索必须在 @ManyToMany 关系中使用的对象时,为什么我会获得这个“传递给持久化的分离实体”? 【发布时间】:2021-12-21 17:01:56 【问题描述】:

我正在使用 Spring Data JPA 开发一个 Spring Boot 项目。我是 Hibernate 映射的新手,我有以下疑问。

注意:我首先实现了我的数据库表,然后我将这些表映射到 Java 实体类中。

我有这个用户类:

@Entity
@Table(name = "portal_user")
@Getter
@Setter
public class User implements Serializable 
     
    private static final long serialVersionUID = 5062673109048808267L;
    
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    
    @Column(name = "first_name")
    private String firstName;
    
    @Column(name = "middle_name")
    private String middleName;
    
    @Column(name = "surname")
    private String surname;
    
    @Column(name = "sex")
    private char sex;
    
    @Column(name = "birthdate")
    private Date birthdate;
    
    @Column(name = "tex_code")
    private String taxCode;
    
    @Column(name = "e_mail")
    private String eMail;
    
    @Column(name = "contact_number")
    private String contactNumber;
    
    @Temporal(TemporalType.DATE)
    @Column(name = "created_at")
    private Date createdAt;
    
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
    @JsonManagedReference
    private Set<Address> addressesList = new HashSet<>();
    
    //@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    //@JsonManagedReference
    //private Set<User_UserType> userToUserTypeAssociation = new HashSet<>();
    
    @ManyToMany(cascade =  CascadeType.ALL )
    @JoinTable(
        name = "portal_user_user_type", 
        joinColumns =  @JoinColumn(name = "portal_user_id_fk") , 
        inverseJoinColumns =  @JoinColumn(name = "user_type_id_fk") 
    )
    //Set<UserType> userTypes;
    List<UserType> userTypes;


    public User(String firstName, String middleName, String surname, char sex, Date birthdate, String taxCode,
            String eMail, String contactNumber, Date createdAt) 
        super();
        this.firstName = firstName;
        this.middleName = middleName;
        this.surname = surname;
        this.sex = sex;
        this.birthdate = birthdate;
        this.taxCode = taxCode;
        this.eMail = eMail;
        this.contactNumber = contactNumber;
        this.createdAt = createdAt;
    
        


如您所见,它包含基于 portal_user_user_type 关联表的 **@ManyToMany 关系:

@ManyToMany(cascade =  CascadeType.ALL )
@JoinTable(
    name = "portal_user_user_type", 
    joinColumns =  @JoinColumn(name = "portal_user_id_fk") , 
    inverseJoinColumns =  @JoinColumn(name = "user_type_id_fk") 
)
//Set<UserType> userTypes;
List<UserType> userTypes;

这是我的 UserType 实体类映射 user_type 数据库表:

@Entity
@Table(name = "user_type")
@Getter
@Setter
public class UserType implements Serializable 
    
    private static final long serialVersionUID = 6904959949570501298L;

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    
    @Column(name = "type_name")
    private String typeName;
    
    @Column(name = "description")
    private String description;
    
    @OneToMany(mappedBy = "userType")
    @JsonManagedReference
    private Set<User_UserType> userToUserTypeAssociation = new HashSet<>();
    

    public UserType() 
        super();
        // TODO Auto-generated constructor stub
    
    
    public UserType(String typeName, String description) 
        super();
        this.typeName = typeName;
        this.description = description;
    


然后我创建了这个 JUnit 测试方法:

@SpringBootTest()
@ContextConfiguration(classes = GetUserWsApplication.class)
@TestMethodOrder(OrderAnnotation.class)
public class UserRepositoryTest 
    
    @Autowired
    private UsersRepository userRepository;
    
    @Autowired 
    UserTypeRepository userTypeRepository;
    
    @Test
    @Order(1)
    public void testInsertUser() 
        
        User user = new User("Luca", null, "Verdi", 'M', new Date(), "XXX", "xxx@gmail.com", "329123456", new Date());
        
        Set<Address> addressesList = new HashSet<>();
        addressesList.add(new Address("Italy", "RM", "00100", "Via XXX 123", "near YYY", user));
        
        user.setAddressesList(addressesList);
        
        //List<UserType> userTypesList = userTypeRepository.findAll();
        List<UserType> userTypesList = new ArrayList<UserType>();

        //Set<UserType> userTypesList = new HashSet<>();
        UserType userType1 = new UserType("ADMIN", "Admin user type !!!");
        UserType userType2 = new UserType("USER", "Just a simple user...");
        
        userTypesList.add(userType1);
        userTypesList.add(userType2);
        
        //user.setUserToUserTypeAssociation(user_UserType_List);
        user.setUserTypes(userTypesList);
        
        userRepository.save(user);
        assertTrue(true);
        
    
    

运行这个测试方法,它按我的预期工作。基本上,它将一条新记录插入到 portal_user 表中(由我的 User 实体类映射),然后将一条记录插入到 user_type 表中(由 UserType 实体类映射),并将关系插入到名为 portal_user_user_typeMany To many 关联表中)。

好的,现在我有以下情况。 UserType 类映射的 user_type 表是一个类型表。它包含与可能的用户类型相关的预定义信息(例如:“ADMIN”、“MODERATOR”、“USER”等)。

所以这个表必须预先填充,我不必在这个表中插入新记录,但我必须在创建新用户时使用现有记录来填充我的 portal_user_user_type 关联表。

所以我的想法是这样的:

    我首先通过 JPA 存储库检索可能的 UserType 实例列表。 与之前的代码不同,为了创建这些 UserType 实例,我将此列表设置到我的用户对象中。

我不知道这是否是正确的策略。无论如何,我已经以这种方式更改了我的单元测试方法的先前代码,但我遇到了一些问题:

@SpringBootTest()
@ContextConfiguration(classes = GetUserWsApplication.class)
@TestMethodOrder(OrderAnnotation.class)
public class UserRepositoryTest 
    
    @Autowired
    private UsersRepository userRepository;
    
    @Autowired 
    UserTypeRepository userTypeRepository;
    
    
    @Test
    @Order(1)
    public void testInsertUser() 
        
        User user = new User("Luca", null, "Verdi", 'M', new Date(), "XXX", "xxx@gmail.com", "329123456", new Date());
        
        Set<Address> addressesList = new HashSet<>();
        addressesList.add(new Address("Italy", "RM", "00100", "Via XXX 123", "near YYY", user));
        
        user.setAddressesList(addressesList);
        
        List<UserType> userTypesList = userTypeRepository.findAll();
        
        user.setUserTypes(userTypesList);
        
        userRepository.save(user);
        assertTrue(true);
        
    
    

如您所见,我首先通过此 JPA 存储库检索用户类型列表,然后设置此列表(而不是我在先前版本的测试方法中手动创建的列表):

List<UserType> userTypesList = userTypeRepository.findAll();
user.setUserTypes(userTypesList);

检索到的用户类型是这样的(这个列表是由我的 userTypeRepository.findAll() 调用检索到的):

所以我使用 setUserTypes() 方法设置它(就像我之前对手动创建的 UserType 对象所做的那样)。

问题是当这行被执行时:

userRepository.save(user);

我得到以下异常:

Hibernate: 
    insert 
    into
        portal_user
        (birthdate, contact_number, created_at, e_mail, first_name, middle_name, sex, surname, tex_code) 
    values
        (?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: 
    insert 
    into
        address
        (country, notes, province, street, fk_user_id, zip_code) 
    values
        (?, ?, ?, ?, ?, ?)

org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: com.easydefi.users.entity.UserType; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.easydefi.users.entity.UserType
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:297)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:551)
    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:152)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
    at jdk.proxy2/jdk.proxy2.$Proxy105.save(Unknown Source)
    at com.easydefi.users.tests.RepositoryTests.UserRepositoryTest.testInsertUser(UserRepositoryTest.java:77)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:84)
    at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.easydefi.users.entity.UserType
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:120)
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:110)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:744)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:712)
    at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:298)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:499)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:423)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:220)
    at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:532)
    at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:463)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:426)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:220)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:153)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:459)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:293)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:123)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:185)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:128)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:55)
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:99)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:720)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:706)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:311)
    at jdk.proxy2/jdk.proxy2.$Proxy102.persist(Unknown Source)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:597)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:289)
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137)
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121)
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:529)
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:599)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:163)
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:138)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
    ... 75 more

问题似乎是这个分离的实体传递给坚持,但这意味着什么?

如何尝试解决此问题?以及首先检索可能的 UserTypes 列表然后插入与这些检索到的用户类型有关系的新用户避免在数据库中再次插入它们的好方法是什么?

【问题讨论】:

【参考方案1】:

这看起来像是您使用的 Cascade 类型的问题。这里你将级联类型设置为CascadeType.ALL

@ManyToMany(cascade =  CascadeType.ALL )
@JoinTable(
    name = "portal_user_user_type", 
    joinColumns =  @JoinColumn(name = "portal_user_id_fk") , 
    inverseJoinColumns =  @JoinColumn(name = "user_type_id_fk") 
)
//Set<UserType> userTypes;
List<UserType> userTypes;

为什么这是一个坏主意?当您对子实体执行CascadeType.ALL 时,它将导致每个数据库操作都传播到实体 UserType。由于 Transaction 是 PERSISTED,因此它也会尝试 PERSIST UserType,但这不起作用,因为 UserType 已经在数据库中。要解决此问题,请改用 CascadeType.MERGE,而 UserType 将自动合并。所以改变这一行:

@ManyToMany(cascade =  CascadeType.MERGE)

另外作为旁注,我假设 UserType 实体是唯一的?因此,请考虑使用 set 而不是 list 来存储它们,因为您不希望重复。

【讨论】:

以上是关于当我第一次检索必须在 @ManyToMany 关系中使用的对象时,为啥我会获得这个“传递给持久化的分离实体”?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django 中一次将多个对象添加到 ManyToMany 关系?

@ManyToMany 保存关系在一个方向上只能使用一次

多对多manytomany

如何在 Kotlin 中使用 JPA ManyToMany 双向关系

Symfony 在具有 ManyToMany 关系的两个表之间具有相同的 @groups

如何直接查询Django为ManyToMany关系创建的表?