nspessot
nspessot

Reputation: 825

how to update an entity with spring data jpa

I have an entity and a Junit, I want to test that update method is working fine, but when I invoke save method from CrudRepository I get a new entry in my table instead of the updated entity.

This is my entity:

@Entity(name = "PERSON")
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "PERSON_ID")
    private Integer id;
    @Column(name = "FIRST_NAME")
    private String firstName;
    @Column(name = "LAST_NAME")
    private String lastName;
//getters and setters
}

This is my service class:

@Service
public class PersonServiceImpl implements PersonService {

    @Autowired
    private PersonRepository personRepository;

    @Override
    public Person updatePerson(Person oldPerson) throws Exception { 

        return personRepository.save(oldPerson);
    }
}

This is my repository

public interface PersonRepository extends CrudRepository<Person, String> {
}

This is my test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { JPAConfigurationTest.class })
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@Transactional
public class UpdatePersonServiceIntegrationTest {
        @Autowired
    PersonService personService;

        @Before
    public void setUp() throws Exception {
        Person person = new Person(1);
        person.setFirstName("Nicolas");
        person.setLastName("Spessot");

        personService.createPerson(person); //This invokes save
    }

        @Test
    public void updatingPerson() throws Exception{
        Person person = new Person(1);
        person.setFirstName("Juan");
        person.setLastName("Riquelme");

        personService.updatePerson(person);

        Person retrieved = personService.retrievePerson(1); //This invokes findOne

        assertEquals(1, person.getId());
        assertEquals("Juan", person.getFirstName());
        assertEquals("Riquelme", person.getLastName());
    }
}

Thanks in advance

Upvotes: 19

Views: 80353

Answers (5)

Badri Paudel
Badri Paudel

Reputation: 1630

One doesn't have to do any complex operations for this. In your service class you can do something like this.

 @Service
public class PersonServiceImpl implements PersonService {

    @Autowired
    private PersonRepository personRepository;

    @Override
    public Person updatePerson(Person oldPerson) throws Exception { 

      oldPerson.setId(oldPerson.getId()) ; // pass the associated id for which you want to update and set that id to the same person [ basically setting the same id to the oldPerson ] this way it will not create new entry because here we are not making new ID ] 

 //oldPerson.set others [ what is to be updated ]  


        return personRepository.save(oldPerson); // now save [old person with updated content but same id as it was before ]
    }
}

This solves the problem of creating new entry to the database and updates the same content with Id associate with that person.

Upvotes: 0

Two ways to make this work

override compareTo method as

@Entity(name = "PERSON")
public class Person implements Comparable<Person>{
 //... all your attributes goes here
 private Integer id;

 @Override
public int compareTo(Person person) {
   return this.getId().compareTo(person.getId());
}} 

or

you need to override equals and hashcode methods in your entity class as below

 @Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (id == null || obj == null || getClass() != obj.getClass())
        return false;
    Person that = (Person) obj;
    return id.equals(that.id);
}
@Override
public int hashCode() {
    return id == null ? 0 : id.hashCode();
}

Upvotes: 0

ciri-cuervo
ciri-cuervo

Reputation: 1756

You must implement equals() and hashCode() in class Person.

@Entity(name = "PERSON")
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "PERSON_ID")
    private Integer id;
    @Column(name = "FIRST_NAME")
    private String firstName;
    @Column(name = "LAST_NAME")
    private String lastName;
    //getters and setters

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (id == null || obj == null || getClass() != obj.getClass())
            return false;
        Person that = (Person) obj;
        return id.equals(that.id);
    }
    @Override
    public int hashCode() {
        return id == null ? 0 : id.hashCode();
    }
}

Upvotes: 5

chinesewhiteboi
chinesewhiteboi

Reputation: 1125

The problem is in your updatePerson method in your service class. Specifically:

return personRepository.save(oldPerson);

All you are currently doing is saving a Person. That's why it is creating a second entry.
What you should do is find the oldPerson first,

Person p = personRepository.findOne(oldPerson.getId())

then update its attributes, and then save it like you did before. Hope that helps.

Upvotes: 28

Koitoer
Koitoer

Reputation: 19533

I think the repository should be

public interface PersonRepository extends CrudRepository<Person, Integer> {

As your Id is Integer not String, also I assume that your

personService.createPerson(person); 

Internally use save method of the repo.

My second advice is the

@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)}

This mean that the app Context need to be generated again also beans, so please be sure that your configuration in persistence.xml is not having h2bml set to create. Also consider to call flush method in your service.

Upvotes: 1

Related Questions