I migrated a Play project from Version 2.3.4 to 2.4.2. The projects uses JPA (Hibernate) and Evolutions. I have an initial Evolutions SQL script, which fills the database with some sample data. This script is now not working anymore, because the Evolutions scripts are now executed before Hibernate generates the tables, which obviously leads to an error. Is this a desired behavior? Is there any way to change the order of execution?
2 Answers
Evolutions are about creation and update database by plain SQL scripts. So if you use some framework that generates data tables itself, like hibernate, then you need to switch off evolutions (or switch off autogeneration and use only evolutions)
Fill database on startup
I have a similar issue on Cassandra, what I did - just create a code that read CQL file and execute it, and run this code after creation the actual data tables.
As I see Hibernate already have this feature - you need to put your custom SQL code into the /import.sql
file in the root of your classpath:
If a file named import.sql exists in the root of the class path ('/import.sql') Hibernate will execute the SQL statements read from the file after the creation of the database schema.
I had the same issue after upgrading to 2.4 from 2.3 My tests did not work since I used Hibernate to create all tables in H2 in memory db and play evolutions for preparing DB with data for tests cases.
My test base was like
public abstract class TestServerBase extends WithServer {
public static String H2_URL = "jdbc:h2:mem:glamazon;MODE=MySQL;REFERENTIAL_INTEGRITY=False";
public abstract String getDb();
@Override
protected FakeApplication provideFakeApplication() {
final String db = getDb();
final Map config = new HashMap();
config.put(String.format("db.%s.driver",db), "org.h2.Driver");
config.put(String.format("db.%s.url",db), H2_URL);
config.put(String.format("db.%s.user",db), "");
config.put(String.format("db.%s.password",db), "");
config.put(String.format("db.%s.jndiName",db), "DefaultDS");
return Helpers.fakeApplication(config);
}
}
Since play 2.4 something has changed and hibernate was called after play evolutions. To deal with this problem I turned of automatic evolutions in my integrationists config
play.evolutions.enabled=false
and I came up with new method for my TestServerBase
@Before
public void runEvolutions(){
final Database db = Databases.createFrom(getDb(),"org.h2.Driver", H2_URL);
JPA.withTransaction(() ->{
Evolutions.applyEvolutions(db);
});
}
@After
public void deleteEvolutions(){
final Database db = Databases.createFrom(getDb(),"org.h2.Driver", H2_URL);
JPA.withTransaction(() ->{
Evolutions.cleanupEvolutions(db);
});
}
I do not agree that we can not use evolutions and Hibernate together. I found using both for integration tests as a perfect solution. If you want to use only evolutions, the problem is that evolutions are DB related so MySQL evolutions do not work with H2 db. Second reason is that I used different evolutions for different test cases and I would need to copy paste all the scripts with scheme for each evolution.
I believe that using Hibernate to create scheme for integration tests is perfectly ok and the 2.4 change is a breaking change which should have been documented.
Here is my repository with working example for play 2.6 but it should be working also with play >= 2.4 githubrepository