Search code examples
javaebean

Ebean @ManyToOne, finder doesn't retrieve all data of related object


I'm using Ebean for my object-mapping and I've made my SQL tables like so

create table company (
  id                int auto_increment not null primary key,
  name              varchar(100)
);

create table employee (
  id                int auto_increment not null primary key,
  name              varchar(100) not null,
  company_id        int not null,
  constraint foreign key (company_id) references company (id)
      on delete restrict on update restrict
);

This is the company Ebean model

import javax.persistence.Entity;
import javax.persistence.Id;
import com.avaje.ebean.Model;
@Entity
public class Company extends Model
{
    @Id
    public Integer id;
    public String name;
}

And employee model

@Entity
public class Employee extends Model
{
    @Id
    public Integer id;
    public String name;
    @ManyToOne
    public Company company;

    public static Finder<Long, Employee> find = new Finder<Long, Employee>(Long.class, Employee.class);
}

When I run the following

Company company = new Company();
company.name = "Microsoft";
company.save();

Employee employee = new Employee();
employee.name = "Mr John";
employee.company = company;
employee.save();

Employee mrJohn = Employee.find.where().eq("id", 1).findUnique();
System.out.println(mrJohn.company.id);
System.out.println(mrJohn.company.name);

The first System.out.println gives 1 (which is the correct id of the company assigned to the employee) but the second shows null (which I expected should have the value "Microsoft"), the output being

1
null

The question therefore is why is only the id of the Company model retrieved, and not the other associated data?


Solution

    1. You can use fetch() to eagerly fetch other parts of the graph. In this case fetch the company name like:

      Employee.find.fetch("company","name").where().eq("id",1).findUnique();

    2. In short field access can not be intercepted (unless you enhance the caller). So using field access for company.name meant that customer.name was a GETFIELD operation and that it was not being intercepted by Ebean and hence lazy loading was not invoked (and hence a null was returned).

    Changing over to use getters/setters meant that lazy loading was invoked when customer.getName() was called.

    Java does not support properties (hance the getters and setters). You can look at other JVM languages that do like Groovy and Kotlin.

    Groovy supports properties, an example using Groovy with @CompileStatic is: https://github.com/ebean-orm/avaje-ebeanorm-examples/blob/master/e-groovy https://github.com/ebean-orm/avaje-ebeanorm-examples/blob/master/e-groovy/src/main/groovy/org/example/domain/Customer.groovy

    Kotlin supports properties, an example is: https://github.com/ebean-orm/avaje-ebeanorm-examples/tree/master/e-kotlin-maven

    Cheers, Rob.