I am running into a strange issue, for which I am not sure what is the best way to solve the problem. I wrote some JPA
entity classes which get persisted into the Database just fine, however when I run in a Spring JUnit
environment, I get the following exception:
org.springframework.dao.InvalidDataAccessApiUsageException: Multiple representations of the same entity [com..x.y.z.Address#0] are being merged. Detached: [com..x.y.z.Address@48d9d51f]; Managed: [com..x.y.z.Address@4a5e389b]; nested exception is java.lang.IllegalStateException: Multiple representations of the same entity [com..x.y.z.Address#0] are being merged. Detached: [com..x.y.z.Address@48d9d51f]; Managed: [com..x.y.z.Address@4a5e389b]
My entity classes are similar to the following:
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;
}
One piece of information, I'd like to add is I am using Spring JPA's CrudRepository
do do the saves.
A simple rendition of my test is as follows:
@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
}
}
What should I do make this run fine in both my test and actual run environment? Thanks
Ok, the way i see it..
Your Address entity has an @Id without any generation strategy, so whatever is in there, will be considered a primary key.
Your cascading all the operation on User to Address:
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
So i am guessing the second time you save the user, it actually tries to merge first..
Now, you create two Address instances without specifying the id.. so it will be 0
in both cases. You save first, that is fine, the you retrieve the User along with the first Address (because of EAGER fetching), and you create another Address and the id will again be the same 0
.
Now you end up with two Addresses with the same id in the list.. one is managed by the persistent context and the other is detached. During merge you get that error.
I cannot prove it for 100% but i have hunch that if you specify the ids for the Address as 1
and 2
respectively (or any two different ones), you will not see that error again.