Offline DB Migration does not work without default server

409 views
Skip to first unread message

Gustavo Bilert

unread,
Jul 5, 2016, 3:13:49 PM7/5/16
to Ebean ORM
Hi,

tl;dr
1) Offline DB Migration depends on having a default server configured, I think it is not the intended behavior.
2) When generating migrations for several platforms, one is interfering on the other.

I am trying to generate migrations, we do not have a default EbeanServer, so at first try I got this error:

javax.persistence.PersistenceException: The default EbeanServer has not been defined? This is normally set via the ebean.datasource.default property. Otherwise it should be registered programmatically via registerServer()
    at com.avaje.ebean.Ebean$ServerManager.getDefaultServer(Ebean.java:179)
    at com.avaje.ebean.Ebean$ServerManager.access$300(Ebean.java:130)
    at com.avaje.ebean.Ebean.getDefaultServer(Ebean.java:267)
    at com.avaje.ebean.dbmigration.DbMigration.setDefaults(DbMigration.java:462)
    at com.avaje.ebean.dbmigration.DbMigration.generateMigration(DbMigration.java:209)

The code is the default example of MainDbMigration, generating only for Postgres.
I worked around this by defining "datasource.default = db", just this, without the actual "db" datasource.

--- Step 2 ----

I need to generate migrations for Postgres and SQLite.
The first change was just replace the setPlatform by addPlatform, then I got this:

2016-07-05 14:52:06 [main] ERROR com.avaje.ebean.Ebean - Error trying to create the default EbeanServer
java.lang.RuntimeException: DataSource user is null?
    at org.avaje.datasource.pool.ConnectionPool.<init>(ConnectionPool.java:204)
    at org.avaje.datasource.Factory.createPool(Factory.java:12)
    at com.avaje.ebeaninternal.server.core.DefaultContainer.getDataSourceFromConfig(DefaultContainer.java:305)

Workaroud:
DbOffline.setPlatform(DbPlatformName.POSTGRES);



--- Step 3 ----

Then I added another addPlatform for SQLite, but it was generating only for Postgres. I almost worked around with this code:

        String version = "1.0.0";
       
System.setProperty("ddl.migration.version", version);

       
DbMigration dbMigration = new DbMigration();
        dbMigration
.addPlatform(DbPlatformName.POSTGRES, "postgres");

       
DbOffline.setPlatform(DbPlatformName.POSTGRES);
        dbMigration
.generateMigration();


       
DbOffline.reset();
       
new File("src/main/resources/dbmigration/model/1.0.0.model.xml").delete();

        dbMigration
= new DbMigration();
        dbMigration
.addPlatform(DbPlatformName.SQLITE, "sqlite");

       
DbOffline.setPlatform(DbPlatformName.SQLITE);
        dbMigration
.generateMigration();

But the first platform affects the second.
If Postgres comes first, UUIDs are generated as "uuid" both for PG and SQLite.
If SQLite comes first, UUIDs are generated as varchar(40) for both.

Rob Bygrave

unread,
Jul 5, 2016, 4:20:25 PM7/5/16
to ebean@googlegroups

The intention is that you can generate multiple at the same time using ..... addPlatform() ... instead of ... setPlatform()

What I'd expect to see is:

        DbMigration dbMigration = new DbMigration();
        dbMigration
.addPlatform(DbPlatformName.POSTGRES, "postgres");
        dbMigration.addPlatform(DbPlatformName.SQLITE, "sqlite");
        dbMigration.generateMigration();

To generate migrations for both postgres and sqlite (and these are generated offline in one go).

Can you try that?

Thanks, Rob.


--

---
You received this message because you are subscribed to the Google Groups "Ebean ORM" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ebean+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Gustavo Bilert

unread,
Jul 5, 2016, 5:17:28 PM7/5/16
to Ebean ORM
I tried not to let the post get long and ended up not being clear.

I had done that, but now I found a way to make it more clear:

The code:

        DbMigration dbMigration = new DbMigration();
        dbMigration
.addPlatform(DbPlatformName.POSTGRES, "postgres");
        dbMigration
.addPlatform(DbPlatformName.SQLITE, "sqlite");
        dbMigration
.generateMigration();


Configuration 1:


datasource
.default=db

datasource
.db.username=sa
datasource
.db.password=
datasource
.db.databaseUrl=jdbc:h2:mem:tests
datasource
.db.databaseDriver=org.h2.Driver

1.0__initial-postgres-.sql:
create table area (
  id                            uuid
not null,
  id_area_type                  uuid
,
  size                          
float,
  version                       bigint
not null,
  create_date                   timestamptz
not null,
  update_date                   timestamptz
not null,
 
...

1.0__initial-sqlite-.sql:
create table area (
  id                            uuid
not null,
  id_area_type                  uuid
,
  size                          
double,
  version                       integer
not null,
  create_date                   timestamp
not null,
  update_date                   timestamp
not null,
 
...

-----------------------------------------------------------------------------------------------------------------------------------------------------

Configuration 2:

datasource.default=db

datasource
.db.username=
datasource
.db.password=
datasource
.db.databaseUrl=jdbc:sqlite:mydb.db
datasource
.db.databaseDriver=org.sqlite.JDBC
datasource
.db.isolationlevel=read_uncommitted


1.0__initial-postgres-.sql:
create table area (
  id                            varchar
(40) not null,
  id_area_type                  varchar
(40),
  size                          
float,
  version                       bigint
not null,
  create_date                   timestamptz
not null,
  update_date                   timestamptz
not null,
 
...


1.0__initial-sqlite-.sql:
create table area (
  id                            varchar
(40) not null,
  id_area_type                  varchar
(40),
  size                          
double,
  version                       integer
not null,
  create_date                   timestamp
not null,
  update_date                   timestamp
not null,
 
...


As you can see, the default datasource is affecting the generated DDL.

Rob Bygrave

unread,
Jul 8, 2016, 8:41:48 AM7/8/16
to Ebean ORM

Right.  Yes this is a bug ... the model.xml should contain the 'logical type' which is then converted to the platform type with the DDL generation.  So the 'logical type' in the model.xml should be UUID but instead it is the actual platform specific type (based on the platform when the model.xml is generated).

So, yes it's a bug.  I'll look into it over the weekend.


Cheers, Rob.

Rob Bygrave

unread,
Jul 11, 2016, 5:41:59 AM7/11/16
to ebean@googlegroups
Hi,


Note that I also logged #770, #771, #772 .. all related to DDL generation in the multiple platform scenario.

#771 - https://github.com/ebean-orm/avaje-ebeanorm/issues/771 ... is a refactor where the DDL for each platform goes into a sub-directory rather than having a suffix. I felt this was a sensible change to make ... the file suffix was not a great idea once we get a few migrations generated.  Hopefully this change is ok for you (and others already using this multi-platform generation feature).

That is all release in 7.18.1 which is on it's way to maven central.


Cheers, Rob. 

Gustavo Bilert

unread,
Jul 27, 2016, 10:58:19 AM7/27/16
to eb...@googlegroups.com
Hello again,

We updated to 7.19.1 to get these fixes. Now we are getting some errors that had not occurred before:

First, we got this:

Exception in thread "main" java.lang.NoClassDefFoundError: org/h2/api/Trigger

It is requiring the H2 driver, but we are using only Postgres and SQLite platforms.

After adding the H2 driver, we got this:

2016-07-27 11:18:59 [main] ERROR j.persistence.PersistenceException - The default EbeanServer has not been defined? This is normally set via the ebean.datasource.default property. Otherwise it should be registered programmatically via registerServer()

So it still needs the default server configured, I expected that that would not be needed, but it is not a big problem, it already informs us what needs to be done.

Then I added a default server (postgres) and got this error:

2016-07-27 11:32:08 [main] ERROR c.a.e.s.deploy.BeanDescriptorManager - Error in deployment
java
.lang.IllegalStateException: Property id not found in [contact, standard, phoneNumber] for type class com.mycompany.customer.contactphone.ContactPhone
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.setBeanReflect(BeanDescriptorManager.java:1340)
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.createByteCode(BeanDescriptorManager.java:1287)
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.readDeployAssociations(BeanDescriptorManager.java:1205)
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.readEntityDeploymentAssociations(BeanDescriptorManager.java:709)
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.deploy(BeanDescriptorManager.java:319)
    at com
.avaje.ebeaninternal.server.core.InternalConfiguration.<init>(InternalConfiguration.java:135)
    at com
.avaje.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:115)
    at com
.avaje.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:75)
    at com
.avaje.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:42)
    at com
.avaje.ebean.EbeanServerFactory.create(EbeanServerFactory.java:55)
    at com
.avaje.ebean.Ebean$ServerManager.getWithCreate(Ebean.java:207)
    at com
.avaje.ebean.Ebean$ServerManager.<init>(Ebean.java:165)
    at com
.avaje.ebean.Ebean$ServerManager.<init>(Ebean.java:130)
    at com
.avaje.ebean.Ebean.<clinit>(Ebean.java:124)
    at com
.avaje.ebean.dbmigration.DbMigration.setDefaults(DbMigration.java:471)
    at com
.avaje.ebean.dbmigration.DbMigration.generateMigration(DbMigration.java:211)
    at com
.mycompany.commons.persistence.dbmigration.MainDbMigration.main(MainDbMigration.java:88)
2016-07-27 11:32:08 [main] ERROR com.avaje.ebean.Ebean - Error trying to create the default EbeanServer
java
.lang.IllegalStateException: Property id not found in [contact, standard, phoneNumber] for type class com.mycompany.customer.contactphone.ContactPhone
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.setBeanReflect(BeanDescriptorManager.java:1340)
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.createByteCode(BeanDescriptorManager.java:1287)
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.readDeployAssociations(BeanDescriptorManager.java:1205)
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.readEntityDeploymentAssociations(BeanDescriptorManager.java:709)
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.deploy(BeanDescriptorManager.java:319)
    at com
.avaje.ebeaninternal.server.core.InternalConfiguration.<init>(InternalConfiguration.java:135)
    at com
.avaje.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:115)
    at com
.avaje.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:75)
    at com
.avaje.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:42)
    at com
.avaje.ebean.EbeanServerFactory.create(EbeanServerFactory.java:55)
    at com
.avaje.ebean.Ebean$ServerManager.getWithCreate(Ebean.java:207)
    at com
.avaje.ebean.Ebean$ServerManager.<init>(Ebean.java:165)
    at com
.avaje.ebean.Ebean$ServerManager.<init>(Ebean.java:130)
    at com
.avaje.ebean.Ebean.<clinit>(Ebean.java:124)
    at com
.avaje.ebean.dbmigration.DbMigration.setDefaults(DbMigration.java:471)
    at com
.avaje.ebean.dbmigration.DbMigration.generateMigration(DbMigration.java:211)
    at com
.mycompany.commons.persistence.dbmigration.MainDbMigration.main(MainDbMigration.java:88)
2016-07-27 11:32:08 [main] ERROR j.lang.ExceptionInInitializerError - null
java
.lang.ExceptionInInitializerError: null
    at com
.avaje.ebean.dbmigration.DbMigration.setDefaults(DbMigration.java:471)
    at com
.avaje.ebean.dbmigration.DbMigration.generateMigration(DbMigration.java:211)
    at com
.mycompany.commons.persistence.dbmigration.MainDbMigration.main(MainDbMigration.java:88)
Caused by: java.lang.RuntimeException: java.lang.IllegalStateException: Property id not found in [contact, standard, phoneNumber] for type class com.mycompany.customer.contactphone.ContactPhone
    at com
.avaje.ebean.Ebean$ServerManager.<init>(Ebean.java:170)
    at com
.avaje.ebean.Ebean$ServerManager.<init>(Ebean.java:130)
    at com
.avaje.ebean.Ebean.<clinit>(Ebean.java:124)
   
... 3 common frames omitted
Caused by: java.lang.IllegalStateException: Property id not found in [contact, standard, phoneNumber] for type class com.mycompany.customer.contactphone.ContactPhone
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.setBeanReflect(BeanDescriptorManager.java:1340)
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.createByteCode(BeanDescriptorManager.java:1287)
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.readDeployAssociations(BeanDescriptorManager.java:1205)
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.readEntityDeploymentAssociations(BeanDescriptorManager.java:709)
    at com
.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.deploy(BeanDescriptorManager.java:319)
    at com
.avaje.ebeaninternal.server.core.InternalConfiguration.<init>(InternalConfiguration.java:135)
    at com
.avaje.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:115)
    at com
.avaje.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:75)
    at com
.avaje.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:42)
    at com
.avaje.ebean.EbeanServerFactory.create(EbeanServerFactory.java:55)
    at com
.avaje.ebean.Ebean$ServerManager.getWithCreate(Ebean.java:207)
    at com
.avaje.ebean.Ebean$ServerManager.<init>(Ebean.java:165)
   
... 5 common frames omitted
2016-07-27 11:32:08 [Thread-3] DEBUG c.a.e.server.lib.ShutdownManager - Shutting down
:generateMigrations FAILED

The mapping is as follows:

@Entity
public class ContactPhone extends BaseEntity implements Serializable {

   
private static final long serialVersionUID = 1L;

   
@NotNull
   
@ManyToOne
//    @JoinColumn(name = "id_contact", nullable = true)
   
private Contact contact;

   
@NotNull
   
private Boolean standard;

   
@Size(max = 40)
//    @Column(length =  40)
   
@NotNull
   
private String phoneNumber;


@MappedSuperclass
public class BaseEntity {

   
@Id
   
private UUID id;

   
@Version
   
Long version;

   
@CreatedTimestamp
   
private Timestamp createDate;

   
@UpdatedTimestamp
   
private Timestamp updateDate;

Those @JoinColumn and @Column are some bad habits people here inherited from hibernate workarounds, we are still trying to purge this.
Anyway, at first it seemed that they were causing the problem, but now the problem persisted even after removing these annotations.


Cheers, Gustavo

Rob Bygrave

unread,
Jul 27, 2016, 7:27:49 PM7/27/16
to ebean@googlegroups
Ok thanks.

I'm sure I introduced those first 2 issues with the change I made.  Yes, we don't want to required H2 or strictly a default server so I'll look at those.

That 3rd one is interesting. It should be seeing the @Id property from BaseEntity so not expecting that error. I wonder if I can reproduce that (I'll try).


Cheers, Rob.


Rob Bygrave

unread,
Jul 30, 2016, 11:55:21 PM7/30/16
to ebean@googlegroups


We need an EbeanServer instance to run the DBMigration and that can be set explicitly via dbMigration.setServer() ... and if that is not set it expects to automatically create the 'default' EbeanServer.  So yes, we need to do one of those (use dbMigration.setServer(ebeanServer) or define a 'default server'.

The 3rd issue I have not been able to reproduce  - IllegalStateException: Property id not found in [contact, standard, phoneNumber] for type class com.mycompany.customer.contactphone.ContactPhone

... I wonder if there is another BaseEntity in your classpath or something like that but I was unable to reproduce by adding BaseEntity and ContactPhone to the example-java8 project.

Cheers, Rob.


Gustavo Bilert

unread,
Aug 18, 2016, 10:00:29 AM8/18/16
to Ebean ORM
Hi, I have found some more information that may be relevant on the 3rd issue:

- We have also updated the enhancer to version 4.11.1.
  We are using Gradle, so we had to use a modified version of this plugin: https://github.com/kt3k/ebean-enhance-plugin
  The modification was just to change the version, because the agentVersion property does not work.

- The IntelliJ plugin of the enhancer also produced the error.

- It may be needed that you have a *ToMany association referencing the entity, like:

@Entity
public class Contact extends BaseEntity implements Serializable {

   
@OneToMany
   
private List<ContactPhone> phones;

   
...
}


Cheers, Gustavo

Rob Bygrave

unread,
Aug 23, 2016, 4:06:26 AM8/23/16
to ebean@googlegroups
At the moment I don't have a reproducing test case.  Can you provide one?

Thanks, Rob.

To unsubscribe from this group and stop receiving emails from it, send an email to ebean+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages