Executive summary:
When I get an object back from play framework's "Finder", that object's ManyToOne field is correctly populated, but the object that it points to itself has OneToMany fields that are erroneously null.
In my app (a "Scenario Repository"), a Scenario has a Game, and Games have many Scenarios.
When I "find" a Scenario
Scenario retrieved_scenario = Scenario.find.where().eq("name", "Test Scenario").findUnique();
the Game object (retrieved_scenario.game) is missing it's scenarios:
assertNotNull(retrieved_scenario); // passes
assertEquals("CM Test", retrieved_scenario.game.name); //passes
assertNotNull("retrived scenario's game's scenarios", retrieved_scenario.game.scenarios); // fails
But if I retreive the Game itself using find for the Game, and test its scenarios list, it is fine.
What am I doing wrong?
Details:
I have an ebean persisted object called a Game that can have many Scenarios:
import play.db.ebean.*;
import com.avaje.ebean.*;
@Entity
public class Game extends Model {
@Id
public String name;
@OneToMany
public List<Scenario> scenarios;
The Scenario object (also ebean persisted) adds itself to the Game's scenario list when it is created:
@Entity
public class Scenario extends Model {
@Id
public String name;
@ManyToOne
public Game game;
@OneToOne
public User author;
public Scenario(String name, String game_name, String author_name) {
Logger.info(String.format("Constructing scenario '%s' of type '%s'", name, game_name));
this.name = name;
this.game = Game.find.where().eq("name", game_name).findUnique();
Logger.info(String.format("...found it's game: '%s', which has %d scenarios", this.game.name, this.game.scenarios.size()));
this.game.scenarios.add(this);
Logger.info(String.format("now ... it's game has %d scenarios", this.game.scenarios.size()));
this.author = User.find.where().eq("username", author_name).findUnique();
}
public static Scenario create(String name, String game_name, String author_name) {
Logger.info(String.format("Creating scenario '%s' of '%s' by '%s'", name, game_name, author_name));
Scenario it = new Scenario(name, game_name, author_name);
it.save();
it.game.save();
it.game.saveManyToManyAssociations("scenarios"); // doesn't help (or apparently hurt)
return it;
}
public static Scenario.Finder<String,Scenario> find =
new Scenario.Finder<String,Scenario>(String.class, Scenario.class);
}
However, when I "find" a scenario using this finder, the scenarios of the associated game are not initialised:
@Test
public void createAndRetrieveScenario() {
Logger.info("testing createAndRetrieveScenario...");
Logger.info("setting up...");
Game created_game = Game.create("CM Test");
Logger.info("creating scenario...");
Scenario created_scenario = Scenario.create("Test Scenario", "CM Test", "GreenAsJade");
assertNotNull(created_scenario);
assertEquals("Test Scenario", created_scenario.name);
assertEquals("CM Test", created_scenario.game.name);
assertNotNull(created_scenario.game.scenarios);
Logger.info("checking that the scenario was added properly to the game...");
Game retrieved_game = Game.find.where().eq("name", "CM Test").findUnique();
assertNotNull("retrieved game", retrieved_game);
assertNotNull("retrieved game scenarios", retrieved_game.scenarios);
Logger.info("retrieving...");
Scenario retrieved_scenario = Scenario.find.where().eq("name", "Test Scenario").findUnique();
assertNotNull(retrieved_scenario);
assertEquals("Test Scenario", retrieved_scenario.name);
assertEquals("CM Test", retrieved_scenario.game.name);
Logger.info("checking scenario's game's scenarios...");
assertNotNull("retrived scenario's game's scenarios", retrieved_scenario.game.scenarios);
assertFalse(retrieved_scenario.game.scenarios.isEmpty());
}
IE the last two asserts fail. But everything up till then seems to work the way I expect. All the log messages that you can see in there report "what you would expect" ...except that interestingly there is no Scenario constructor call associated with the find() operation, which does return a Scenario!
What am I doing wrong here?
Thanks!
Extra info:
The output of running the test, after applying the changes suggested by SpartanElite, with SQL logging on, is here: http://pastebin.com/BbMrCtZL
These are the exact source of ScenarioTest.java Scenario.java and Game.java that produced the results.
-A tarball of the whole thing is here: http://bit.ly/onetomanytest. You should be able to extract it, cd to it, run play, and do test-only models.ScenarioTest to see the result. There is nothing in there other than this stuff and a User model.