" org.springframework.dao.InvalidDataAccessApiUsageException:同一个"的多个表示。在运行Spring Integration Test时

时间:2017-01-30 22:31:46

标签: java spring jpa spring-data-jpa spring-junit

我遇到了一个奇怪的问题,我不知道解决问题的最佳方法是什么。我编写了一些JPA实体类,它们可以很好地保存到数据库中,但是当我在Spring JUnit环境中运行时,我得到以下异常:

  

org.springframework.dao.InvalidDataAccessApiUsageException:Multiple   正在存在同一实体[com..x.y.z.Address#0]的表示   合并。分离:[com..x.y.z.Address @ 48d9d51f];管理:   [com..x.y.z.Address @ 4a5e389b];嵌套异常是   java.lang.IllegalStateException:相同的多个表示   实体[com..x.y.z.Address#0]正在合并。独立:   [com..x.y.z.Address @ 48d9d51f];管理:[com..x.y.z.Address @ 4a5e389b]

我的实体类与以下内容类似:

class User {

   @Id   
   @SequenceGenerator(name = "USER_ID_GENERATOR", sequenceName = "USER_SEQ")
   @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_ID_GENERATOR") 
   private String id;

   @OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
   private Set<Address> addresses = new HashSet<>();
}

class Address{
  @Id
  private long addressId;

  private String addressLine;

  @ManyToOne 
  @JoinColumn(name="user_id") 
  private User user;
}

我要添加的一条信息就是我正在使用Spring JPA&#39; CrudRepository进行保存。

我的测试的简单演绎如下:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {MyApplication.class})
@WebIntegrationTest({ "server.port=12345", "server.url=http://127.0.0.1:12345" })
@DirtiesContext
public class MyIntegrationTest {

 private UserRepository userRepository

 @Test
 public void testSave(){
   User user = new User(1, "James");
   Address address1 = new Address("1234 xyz street");
   user.addAddress(address1);

   userRepository.save(user);

   User user = userRepository.findById(1);
   Address address2 = new Address("111 abc street");
   user.addAddress(address2);
   userRepository.save(user) // this is where the exception happens while running the test
 }
}

我应该怎么做才能在我的测试和实际运行环境中都运行良好?感谢

1 个答案:

答案 0 :(得分:2)

好的,我看到它的方式..

你的地址实体有一个没有任何生成策略的@Id,所以无论在那里,它都会被视为主键。

您级联用户到地址的所有操作:

@OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)

所以我猜你第二次保存用户,它实际上是先尝试合并..

现在,您创建两个Address实例而不指定id ..因此在两种情况下它都是0。你首先保存,没关系,你检索用户和第一个地址(因为EAGER提取),你创建另一个地址,id将再次相同0

现在你最终在列表中有两个具有相同id的地址。一个由持久化上下文管理,另一个是分离的。 在合并期间,您会收到该错误。

我无法100%证明这一点,但我预感到,如果您分别将地址的ID指定为12(或任何两个不同的地址),您将看不到该错误试。