Edito
Edito

Reputation: 3747

Does Jpa @Repository automatically update the object when a setter is called?

While programming in test driven development I stumbled upon a strange thing. My test does not fail, even when I don't update the object to the database.

    @Test
    public void testStartCircleSession(){
        Circle circle=circleSessionService.createCircle(defaultTheme,2,2,GameMode.ONLINE);
        circle.setGameStatus(GameStatus.STARTED);

        //circleSessionService.updateCircle(defaultCircle); --> this calls the update method
        Circle circleFromRepo=circleRepository.findOne(circle.getId());
        assertThat(circleFromRepo.getGameStatus(),equalTo(circle.getGameStatus()));
    }

By default the gamemode gets set to PLANNED yet the test finished successfully without having called the update method. So I strongly believe Jpa updated the object when a setter is called, but I'm not sure.

Circle DOM

package be.kdg.kandoe.backend.dom;

import be.kdg.kandoe.backend.dom.participations.CircleParticipation;
import be.kdg.kandoe.backend.dom.roles.Role;
import javafx.beans.DefaultProperty;
import org.springframework.hateoas.Identifiable;

import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "Circle")
public class Circle implements Serializable, Identifiable<Integer>{
    @Id
    @GeneratedValue
    @Column(name = "CircleId", nullable = false)
    private Integer circleId;

    @OneToMany(targetEntity = CircleParticipation.class,cascade = CascadeType.ALL,fetch = FetchType.EAGER,mappedBy = "circle")
    private List<CircleParticipation> circleParticipations;

    @OneToMany(targetEntity = Card.class,cascade = CascadeType.ALL,fetch = FetchType.EAGER,mappedBy = "circle")
    private List<Card> cards;

    @OneToMany(targetEntity = Vote.class,cascade = CascadeType.ALL,fetch = FetchType.EAGER,mappedBy = "circle")
    private List<Vote> votes;

    @OneToOne(targetEntity = Theme.class, cascade = CascadeType.ALL,fetch = FetchType.EAGER)
    @JoinColumn(name="ThemeId",nullable = false)
    private Theme theme;

    @Column(name = "GameMode", nullable = false)
    @Enumerated(EnumType.STRING)
    private GameMode gameMode;

    @Column(name = "GameStatus", nullable = false)//,columnDefinition ="PLANNED")
    @Enumerated(EnumType.STRING)
    private GameStatus gameStatus;

    @Column(name = "TurnTime", nullable = false)
    private Integer turnTime;

    @Column(name = "TotalRounds", nullable = false)
    private Integer totalRounds;

    @OneToOne(targetEntity = CircleParticipation.class, cascade = CascadeType.ALL,fetch = FetchType.EAGER)
    @JoinColumn(name="CurrentCircleParticipationId") //current user
    private CircleParticipation currentCircleParticipation;

    @Column(name = "CurrentRound", nullable = false)
    private Integer currentRound;


    public CircleParticipation getCurrentCircleParticipation() {
        return currentCircleParticipation;
    }

    public void setCurrentCircleParticipation(CircleParticipation currentCircleParticipation) {
        this.currentCircleParticipation = currentCircleParticipation;
    }

    public GameMode getGameMode() {
        return gameMode;
    }


    public Integer getTurnTime() {
        return turnTime;
    }

    public Integer getTotalRounds() {
        return totalRounds;
    }

    public Circle(Theme theme, int turnTime, int totalRounds, GameMode mode){
        this.theme = theme;
        this.turnTime = turnTime;
        this.totalRounds = totalRounds;
        this.gameMode = mode;
        this.currentRound=1;
        circleParticipations = new ArrayList<>();
        gameStatus=GameStatus.PLANNED;

    }

    public Circle() {
        circleParticipations = new ArrayList<>();
    }

    public Integer getCircleId() {
        return circleId;
    }

    public List<Vote> getVotes() {
        return votes;
    }


    public List<Card> getCards() {
        return cards;
    }

    public Theme getTheme() {
        return theme;
    }

    @Override
    public Integer getId() {
        return circleId;
    }

    public List<CircleParticipation> getCircleParticipations() {
        return circleParticipations;
    }

    public Integer getCurrentRound() {
        return currentRound;
    }


    public void setCurrentRound(int currentRound) {
        this.currentRound = currentRound;
    }

    public CircleParticipation getCreatorParticipation() {
        return this.circleParticipations.stream().filter(p->p.getRoles().contains(Role.toRole(Role.RoleType.CREATOR))).findFirst().get();
    }

    public GameStatus getGameStatus() {
        return gameStatus;
    }

    public void setGameStatus(GameStatus gameStatus) {
        this.gameStatus = gameStatus;
    }
}

Repo

package be.kdg.kandoe.backend.persistence.api;

import be.kdg.kandoe.backend.dom.Circle;
import be.kdg.kandoe.backend.dom.Theme;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

/**
 * Created by claudiu on 23/02/16.
 */
public interface CircleRepository extends JpaRepository<Circle,Integer>, JpaSpecificationExecutor<Circle> {
}

Upvotes: 2

Views: 2626

Answers (2)

K.Nicholas
K.Nicholas

Reputation: 11551

I would have to say yes. I did a test, but slightly different than what you have done.

I first created a Car and set the type to honda, similar to what you did:

Car car = new Car();
carRepository.save(car);
car.setType("honda");    
System.out.println("CAR="+car);

Notice that the save is done before the type is set. Not surprisingly, the Car prints out as type "honda":

CAR=Car:1:honda

When I do a separate fetch, in an entirely different ServiceImpl call, the type is still "honda"

Car c = carRepository.findOne(id);
System.out.println("CAR="+c);

Which seems to indicate that the car type was saved at least in a cache somewhere. However, I understand that object caches, which I think are level II caches, are not enabled by default, which I haven't done.

Still, to check further, I added a change car method:

Car c = carRepository.findOne(id);
c.setType("toyota");
System.out.println("CAR="+c);

Here, of course, the car prints out as type = "Toyota", as expected:

CAR=Car:1:toyota

But what indicates that setting the field has resulted in an update in the database is two things. The first, and most conclusive, is there is an database update statement from hibernate after I exit the method:

Hibernate: update car set type=? where id=?

And, secondly, there the type returned from a subsequent and separate find:

Car c = carRepository.findOne(id);
System.out.println("CAR="+c);

shows the type as a "Toyota":

CAR=Car:1:toyota

Upvotes: 3

kakashi hatake
kakashi hatake

Reputation: 1185

you are trying to repeat the process after the end of the transaction that you have achieved try this

@Test
    public void testStartCircleSession(){
        Circle circle=Circle(defaultTheme,2,2,GameMode.ONLINE).setGameStatus(GameStatus.STARTED);

        circleSessionService.createCircle(circle);
        Circle circleFromRepo=circleRepository.findOne(circle.getId());
        assertThat(circleFromRepo.getGameStatus(),equalTo(circle.getGameStatus()));
    }

Upvotes: 0

Related Questions