Search code examples
javaplayframeworkebean

Ebean and Play! not filtering columns with .select()


I'm trying to fetch just a part of the model using Ebean in Play! Framework, but I'm having some problems and I didn't found any solutions.

I have these models:

User:

@Entity
@Table(name = "users")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class User extends Model{
    @Id
    private int id;
    @NotNull
    @Column(name = "first_name", nullable = false)
    private String firstName;
    @Column(name = "last_name")
    private String lastName;
    @NotNull
    @Column(nullable = false)
    private String username;
    @NotNull
    @Column(nullable = false)
    private String email;
    private String gender;
    private String locale;
    private Date birthday;
    private String bio;
    @NotNull
    @Column(nullable = false)
    private boolean active;
    private String avatar;
    @Column(name = "created_at",nullable = false)
    private Date createdAt;

    @OneToMany
    private List<UserToken> userTokens;

    // Getters and Setters omitted for brevity
}

UserToken:

@Entity
@Table(name = "user_tokens")
public class UserToken extends Model {
    @Id
    private int id;
    @Column(name = "user_id")
    private int userId;
    private String token;
    @Column(name = "created_at")
    @CreatedTimestamp
    private Date createdAt;

    @ManyToOne
    private User user;

    // Getters and Setters omitted for brevity
}

And then, I have a controller UserController:

public class UserController extends Controller{
    public static Result list(){
        User user = Ebean.find(User.class).select("firstName").where().idEq(1).findUnique();
        return Results.ok(Json.toJson(user));
    }
}

I expected that, when using the .select(), it would filter the fields and load a partial object, but it loads it entirely. In the logs, there is more problems that I don't know why its happening.

Statements logs

It is making 3 queries. First is the one that I want. And then it makes one to fetch the whole Model, and another one to find the UserTokens. I don't know why it is doing these last two queries and I wanted just the first one to be executed.

Solution Edit

After already accepted the fact that I would have to build the Json as suggested by @biesior , I found (out of nowhere) the solution!

public static Result list() throws JsonProcessingException {
    User user = Ebean.find(User.class).select("firstName").where().idEq(1).findUnique();
    JsonContext jc = Ebean.createJsonContext();
    return Results.ok(jc.toJsonString(user));
}

I render only the wanted fields selected in .select() after using JsonContext.


Solution

  • That's simple, when you using select("...") it always gets just id field (cannot be avoided - it's required for mapping) + desired fields, but if later you are trying to access the field that wasn't available in first select("...") - Ebean repeats the query and maps whole object.

    In other words, you are accessing somewhere the field that wasn't available in first query, analyze your controller and/or templates, find all fields and add it to your select (even if i.e. they're commented with common HTML comment in the view!)