4
@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();
    }
}
Community
  • 1
  • 1
coding_idiot
  • 13,526
  • 10
  • 65
  • 116
  • what is `flushAndClear();`? is it a method of your test case? - does it really do what its name says? - It flushAndClear is correct, then I would expect the problem is related to the relation mapping - would you please post the relevant snippets. – Ralph Nov 07 '15 at 21:03
  • @Ralph I am trying to move a project to `spring-data`, it contained `flushAndClear` implementation, as of now, the method is blank. Updated the question with relevant snippets. – coding_idiot Nov 07 '15 at 21:36
  • 1
    Well, if it's blank, it doesn't do anything, so the game2 that is retrieved from the last findOne() is the one that was stored in the session cache before, and that had a null players list. So what you see is expected.Make it really flush and clear. – JB Nizet Nov 07 '15 at 22:05
  • @JBNizet yeah, unable to figure out how to do that using `spring-data-jpa`. – coding_idiot Nov 08 '15 at 06:27
  • 1
    Inject the EntityManager in the test (using the `@PersistenceContext` annotation), and call flush() and clear() on it. – JB Nizet Nov 08 '15 at 07:37
  • @JBNizet awesome, it worked. I remember trying that earlier with `@Autowired`, may be `@PersistenceContext` did the magic. – coding_idiot Nov 08 '15 at 08:56

1 Answers1

7

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();
   }

}
Ralph
  • 118,862
  • 56
  • 287
  • 383