coding_idiot
coding_idiot

Reputation: 13734

Spring Data Jpa Test returns null list even after child is saved

@Test
public void testAddPlayerToGame() {
    gameRepository.save(createTestGame());
    Game game = gameRepository.findOne(1l);
    assertTrue(game.getId() > 0);
    Player p = new Player();
    p.setName("test 1");
    p.setGame(game);
    p.setChips(5000);
    assertTrue(p.getId() == null);
    playerRepository.saveAndFlush(p);
    assertTrue(p.getId() != null);

    flushAndClear();
    Game game2 = gameRepository.findOne(1l);
    assertEquals(1, game2.getPlayers().size());
}

The above test fails because game2.getPlayers() returns null.

Already went through JpaRepository caches newly created object. How to refresh it? but couldn't figure out how to solve.

The method flushAndClear used in the above code is blank, as follows :

protected void flushAndClear() {
//        sessionFactory.getCurrentSession().flush();
//        sessionFactory.getCurrentSession().clear();
    }

Any help is really appreciated.

Update

Game & Player mapping code :

@Entity
@Table(name="game")
public class Game implements Serializable {

    private static final long serialVersionUID = -495064662454346171L;
    private long id;
    private int playersRemaining;
    private Player playerInBTN;
    private GameType gameType;
    private String name;
    private boolean isStarted;
    private Set<Player> players;
    private HandEntity currentHand;
    private GameStructure gameStructure;

    @Column(name="game_id")
    @Id
    @GeneratedValue(strategy=GenerationType.TABLE)
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }

    @Column(name="players_left")
    public int getPlayersRemaining() {
        return playersRemaining;
    }
    public void setPlayersRemaining(int playersRemaining) {
        this.playersRemaining = playersRemaining;
    }

    @OneToOne
    @JoinColumn(name="btn_player_id")
    public Player getPlayerInBTN(){
        return playerInBTN;
    }
    public void setPlayerInBTN(Player playerInBTN){
        this.playerInBTN = playerInBTN;
    }

    @Column(name="game_type")
    @Enumerated(EnumType.STRING)
    public GameType getGameType() {
        return gameType;
    }
    public void setGameType(GameType gameType) {
        this.gameType = gameType;
    }

    @OneToMany(mappedBy="game", fetch=FetchType.LAZY)
    public Set<Player> getPlayers() {
        return players;
    }
    public void setPlayers(Set<Player> players) {
        this.players = players;
    }

    @Column(name="name")
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Column(name="is_started")
    public boolean isStarted() {
        return isStarted;
    }
    public void setStarted(boolean isStarted) {
        this.isStarted = isStarted;
    }

    @OneToOne(fetch=FetchType.EAGER)
    @JoinColumn(name="current_hand_id")
    public HandEntity getCurrentHand() {
        return currentHand;
    }
    public void setCurrentHand(HandEntity currentHand) {
        this.currentHand = currentHand;
    }

    @OneToOne(fetch=FetchType.EAGER, cascade={CascadeType.ALL})
    @JoinColumn(name="game_structure_id")
    public GameStructure getGameStructure() {
        return gameStructure;
    }
    public void setGameStructure(GameStructure gameStructure) {
        this.gameStructure = gameStructure;
    }
}


@Entity
@Table(name="player")
public class Player implements Comparable<Player>, Serializable{

    private static final long serialVersionUID = -1384636077333014255L;
    private String id;
    private Game game;
    private String name;
    private int chips;
    private int gamePosition;
    private int finishPosition;
    private boolean sittingOut;

    @JsonIgnore
    @Column(name="player_id")
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid2")
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }

    @JsonIgnore
    @ManyToOne
    @JoinColumn(name="game_id")
    public Game getGame() {
        return game;
    }
    public void setGame(Game game) {
        this.game = game;
    }

    @Column(name="name")
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Column(name="chips")
    public int getChips() {
        return chips;
    }
    public void setChips(int chips) {
        this.chips = chips;
    }

    @Column(name="game_position")
    public int getGamePosition() {
        return gamePosition;
    }
    public void setGamePosition(int gamePosition) {
        this.gamePosition = gamePosition;
    }

    @Column(name="finished_place")
    public int getFinishPosition() {
        return finishPosition;
    }
    public void setFinishPosition(int finishPosition) {
        this.finishPosition = finishPosition;
    }

    @Column(name="sitting_out")
    public boolean isSittingOut() {
        return sittingOut;
    }
    public void setSittingOut(boolean sittingOut) {
        this.sittingOut = sittingOut;
    }

    @Override
    public boolean equals(Object o){
        if(o == null || !(o instanceof Player)){
            return false;
        }
        Player p = (Player) o;
        if(this.getId() == null){
            return this.getName().equals(p.getName());
        }
        return this.getId().equals(p.getId());
    }

    @Override
    public int hashCode(){
        if(id == null){
            return name.hashCode();
        }
        return id.hashCode();
    }

    @Override
    @Transient
    public int compareTo(Player p){
        return this.getGamePosition() - p.getGamePosition();
    }
}

I am using HSQL db in the testing environment. Following is the configuration :

@Configuration
@EnableJpaRepositories(basePackages = "com.nitinsurana.repos")
@EnableTransactionManagement
class TestDataConfig {

    @Bean(name = "transactionManager")
    @Autowired
    public PlatformTransactionManager getTransactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
        jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
        return jpaTransactionManager;
    }

    @Bean
    public EntityManagerFactory entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan("com.nitinsurana.domain");
        em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        em.setJpaProperties(getHibernateProperties());
        em.afterPropertiesSet();
        return em.getObject();
    }

//    @Bean
//    public EntityManager entityManager(HibernateEntityManagerFactory entityManagerFactory) {
//        HibernateEntityManager entityManager = (HibernateEntityManager) entityManagerFactory.createEntityManager();
//        entityManager.setFlushMode(FlushModeType.AUTO FlushMode.ALWAYS);
//        return entityManager;
//    }

    private Properties getHibernateProperties() {
        Properties prop = new Properties();
        prop.put("hibernate.show_sql", "false");
        prop.put("hibernate.hbm2ddl.auto", "create");
        prop.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
        return prop;
    }

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.HSQL)
//                .addScript("classpath:com/bank/config/sql/schema.sql")
//                .addScript("classpath:com/bank/config/sql/test-data.sql")
                .build();
    }
}

Upvotes: 4

Views: 2989

Answers (1)

Ralph
Ralph

Reputation: 120851

You need to write a FlushAndClear method that works. If not game2 gets not loaded for the database but from the internal cache. And if it is not loaded then the releationship become not updated.

class TestXXX {

   @PersistenceContext
   private EntityManager em.

   private flushAndClear() {
      em.flush();
      em.clear();
   }

}

Upvotes: 7

Related Questions