UnsupportedOperationException合并保存与hibernate和JPA的多对多关系

UnsupportedOperationException合并保存与hibernate和JPA的多对多关系,hibernate,jpa,many-to-many,Hibernate,Jpa,Many To Many,我已经设置了一个简单的多对多关系帐户:角色与Hibernate,但当我尝试在添加了角色后在单元测试中保存帐户时,我得到一个不支持的操作异常: java.lang.UnsupportedOperationException at java.util.AbstractList.remove(AbstractList.java:144) at java.util.AbstractList$Itr.remove(AbstractList.java:360) at java.uti

我已经设置了一个简单的多对多关系帐户:角色与Hibernate,但当我尝试在添加了角色后在单元测试中保存帐户时,我得到一个不支持的操作异常:

java.lang.UnsupportedOperationException
    at java.util.AbstractList.remove(AbstractList.java:144)
    at java.util.AbstractList$Itr.remove(AbstractList.java:360)
    at java.util.AbstractList.removeRange(AbstractList.java:559)
    at java.util.AbstractList.clear(AbstractList.java:217)
    at org.hibernate.type.CollectionType.replaceElements(CollectionType.java:502)
    at org.hibernate.type.CollectionType.replace(CollectionType.java:582)
    at org.hibernate.type.TypeHelper.replace(TypeHelper.java:178)
    at org.hibernate.event.def.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:563)
    at org.hibernate.event.def.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:288)
    at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:261)
    at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:84)
    at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:867)
    at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:851)
    at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:855)
    at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:686)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
    at $Proxy33.merge(Unknown Source)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:360)
    at ....JpaProvider.save(JpaProvider.java:161)
    at ....DataModelTest.testAccountRole(DataModelTest.java:47)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
这里怎么了?我的实体设置是否有问题,或者这是hibernate或JPA限制迫使我将m:m关系拆分为3个1:n关系,并对m:n关系表进行建模(我希望避免这种情况,因为它没有任何附加信息)。我已经在我的原型中对其他1:n实体进行了建模,到目前为止,这似乎运行得很好

这是我的设置,任何关于它是否有问题的想法都将不胜感激

实体(简化):

MockAccount(与MockRole相同):

最后,提供者:

@Repository
public class AccountProvider extends JpaProvider<Account, Long> {

}
@存储库
公共类AccountProvider扩展了JPAPProvider{
}
其中JPAProvider只是包装了许多JPA还原方法(至少在这种情况下是重要的):

公共抽象类JpaProvider实现了JpaRepository、JpaSpecificationExecutor、querydsldpredicateexecutor{
...
}
你知道为什么拯救行动可能是不支持的吗

这是因为你的

Arrays.asList(roleProvider.findAll().get(0))
这将创建一个不可修改的列表(实际上是一个不可调整大小的列表)。Hibernate似乎期待一个可修改的列表。请尝试使用此选项:

public void testAccountRole(){      
    Account returnedAccount = accountProvider.findAll().get(0);

    List<Role> list = new ArrayList<Role>();
    list.add(roleProvider.findAll().get(0));    
    returnedAccount.setRoles(list);  

    accountProvider.save(returnedAccount);
}
public void testAccountRole(){
Account returnedAccount=accountProvider.findAll().get(0);
列表=新的ArrayList();
add(roleProvider.findAll().get(0));
returnedAccount.setRoles(列表);
accountProvider.save(returnedAccount);
}

此解决方案不会解释为什么会出现另一个异常(可能在Hibernate文档中有记录),但它可能是一个有效的解决方法。

Hibernate的
集合的持久化变体试图委托给抽象基类(
PersistenceBag
)这没有实现
add
方法

嘿,谢谢你的即时回复!我现在正把头撞在桌子上!当我的同事看了看我的报告说“你为什么不那样做呢?”,我就有这种感觉啊,好吧。。再次工作,我很高兴!我对使用列表的Kotlin代码也有同样的问题(因此是不可变的),我花了几个小时才偶然发现这个答案。我把我的代码改成了使用可变列表,它很有效。它真的救了我的命!!唯一让我难过的是,即使启用了最低级别的日志,它也无法显示任何相关信息来帮助找到真正的原因。Kotlin也是如此!将我的“toList()”更改为“toMutableList()”,一切都很好!幸运的是,我立刻找到了答案。你帮我节省了几个小时,这似乎是有线的,但修复工作,这是在我的情况下的问题。解决方案是从Hibernate托管实体获取基于PersistenceBag的集合,将其添加到非托管arraylist,然后将我的新条目添加到该arraylist,然后在Hibernate托管实体上调用该集合的setter。
@Repository
public class AccountProvider extends JpaProvider<Account, Long> {

}
public abstract class JpaProvider<T extends Object, ID extends Serializable> implements JpaRepository<T, ID>, JpaSpecificationExecutor<T>, QueryDslPredicateExecutor<T> {
...
}
Arrays.asList(roleProvider.findAll().get(0))
public void testAccountRole(){      
    Account returnedAccount = accountProvider.findAll().get(0);

    List<Role> list = new ArrayList<Role>();
    list.add(roleProvider.findAll().get(0));    
    returnedAccount.setRoles(list);  

    accountProvider.save(returnedAccount);
}