Tôi đã thiết lập một tài khoản quan hệ nhiều-nhiều đơn giản: vai trò với Hibernate nhưng khi tôi cố gắng lưu một tài khoản trong một bài kiểm tra đơn vị sau khi nó có đã thêm vai trò của mình, tôi nhận được UnsupportedOperationException:UnsupportedOperationException hợp nhất tiết kiệm quan hệ nhiều-nhiều với hibernate và JPA
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)
Có gì xảy ra ở đây? Là thiết lập thực thể của tôi bị lỗi hoặc là một giới hạn ngủ đông hoặc JPA buộc tôi phải chia tách mối quan hệ m: m của tôi thành mối quan hệ 3: n mô hình hóa bảng quan hệ m: n (mà tôi muốn tránh vì nó không có bất kỳ thông tin thêm). Tôi đã mô hình hóa các thực thể 1: n khác trong nguyên mẫu của mình và dường như hoạt động tốt cho đến nay ...
Đây là thiết lập của tôi, bất kỳ suy nghĩ nào có thể bị lỗi.
Đối tượng (giản thể):
@Entity
@Table(name="account")
public class Account extends AbstractPersistable<Long> {
private static final long serialVersionUID = 627519641892468240L;
private String username;
@ManyToMany
@JoinTable(name = "account_roles",
joinColumns = { @JoinColumn(name = "account_id")},
inverseJoinColumns={@JoinColumn(name="role_id")})
private List<Role> roles;
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
@Entity
@Table(name="role")
public class Role extends AbstractPersistable<Long> {
private static final long serialVersionUID = 8127092070228048914L;
private String name;
@ManyToMany
@JoinTable(name = "account_roles",
joinColumns={@JoinColumn(name="role_id")},
inverseJoinColumns={@JoinColumn(name="account_id")})
private List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
Unit Test:
@TransactionConfiguration
@ContextConfiguration({"classpath:dw-security-context-test.xml"})
@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
public class DataModelTest {
@Inject
private AccountProvider accountProvider;
@Inject
private RoleProvider roleProvider;
@Before
public void mockAccountRolePermission(){
Account account = MockAccount.getSavedInstance(accountProvider);
Role role = MockRole.getSavedInstance(roleProvider);
}
@Test
public void testAccountRole(){
Account returnedAccount = accountProvider.findAll().get(0);
returnedAccount.setRoles(Arrays.asList(roleProvider.findAll().get(0)));
accountProvider.save(returnedAccount);
}
}
MockAccount (tương tự cho MockRole):
public class MockAccount {
public static Account getInstance(){
Account account = new Account();
account.setUsername(RandomData.rndStr("userName-", 5));
return account;
}
public static Account getSavedInstance(AccountProvider accountProvider){
Account account = getInstance();
accountProvider.save(account);
return account;
}
}
Và cuối cùng các nhà cung cấp:
@Repository
public class AccountProvider extends JpaProvider<Account, Long> {
}
nơi JPAProvider chỉ kết thúc tốt đẹp rất nhiều phương pháp JPARepository (ít nhất là như xa như điều quan trọng là trong trường hợp này):
public abstract class JpaProvider<T extends Object, ID extends Serializable> implements JpaRepository<T, ID>, JpaSpecificationExecutor<T>, QueryDslPredicateExecutor<T> {
...
}
Bất kỳ ý tưởng về lý do tiết kiệm có thể là một UnsupportedOperation?
Xin chào, cảm ơn bạn đã trả lời ngay! Tôi đang đập đầu vào bàn ngay lúc này! Tôi đã có nó chỉ như thế khi đồng nghiệp của tôi nhìn qua của tôi nên nói "tại sao bạn không làm điều đó như thế ..?" ;) Ah well .. làm việc một lần nữa, hạnh phúc cho tôi! – Pete