Eager fetch does not seem to join

匿名 (未验证) 提交于 2019-12-03 07:50:05

问题:

I'm using play 2.0.4 with Java. I'm trying to save and retrieve a value from the in-memory db that play provides (Ebean is the underlying JPA implementation). Here's some sample code:

@NoobDisclaimer ("I'm fairly new to Play and JPA") @Entity public class User extends Model {  @Id public Long id;  public String name;  // Does not fetch eagerly. @ManyToOne(fetch=FetchType.EAGER) private Role role; // Role extends Model { has id and name}  public static Finder<Long, User> find = new Finder<Long, User>(Long.class, User.class);  public static List<User> all() {     List<User> allUsers = find.all();     for (User u : allUsers) {         System.out.println("User:" + u.id + "|" + u.name); // SOP1         // System.out.println("Assoc Role:" + u.role.name); //SOP2     }     return allUsers; }  public static void create(User user) {     user.save(); }

}

In index.scala.html, @(users: List[User], userForm: Form[User])

<h2>@users.size() user(s) found!</h2>         <ul>             @for(usr <- users) {                 <li>Name: @usr.name</li> <!-- Displayed -->                 <li>Role: @usr.role.name</li> <!-- Displays blank value -->             }         </ul>

The problem is that when I do a User.all() in the controller and send it to the view, user.role is not loaded, i.e., @usr.role.name is blank. There is no exception. I have set SQL debugging on and I have verified that a foreign key to the Role table is saved in the User table. When I print the role name in the User.all() method (see SOP2), a query is fired and the role name is printed. It also shows up on the view.

I understand that, by default, the role would be lazily loaded and that the PersistenceContext would not be available in the template to load the role associated with the user. However, shouldn't an eager fetch get me all assocaited entites for an object? I'm fairly new to Play and JPA and I can't figure out how to get this to work without going through each associated entity when I load something. Is there something I'm missing?

On a related note, if I had to use lazy fetch, how do I ensure that the user.role is available to the view when I fetch a user?

回答1:

Ebean is the underlying JPA implementation

Ebean is not a JPA Implementation. Ebean has a little in common with the JPA standard. It looks a little similar, because it's annotations look similar to JPA's.

Cause of your problem: Ebean does not support fetch=... attribute on @ManyToMany annotation.

2 solutions:

  1. Remove fetch=... from annotation and instead use fetch() method on either the play.db.ebean.Model.Finder<I,T> object (which implements com.avaje.ebean.Query<T>) or the com.avaje.ebean.Ebean object.

    Problem is there are two separate persistent libraries here (play.db.ebean and com.avaje.ebean) and integration between them is a challenge and issue.
    E.g. play.db.ebean.Model.Finder.fetch() method returns com.avaje.ebean.Query<T> rather than play.db.ebean.Model.Finder - which I find unhelpful as it takes you away from the play API Model helper. After calling fetch() apparently you can no longer use the Model.Finder methods - not much of a "helper" class at that point.
    To be honest, I don't think the fetch functionality is a first class feature within Play API yet - best to defer to the Avaje API.

    Two examples of using fetch() from within the Avaje API:

    // single SQL query with a fetch join List<Order> l0 = Ebean.find(Order.class) .fetch("customer") .findList();

    and

    // two separate SQL queries List<Order> l0 = Ebean.find(Order.class) .fetch("customer", new FetchConfig().query()) .findList();

    Note: the last release/update to Ebean (other that bug fixes) was 6 Nov 2010 - 2 full years ago. The uptake rate of Ebean is very low.

  2. Switch to using a JPA 2.0 implementation within Play. The 2.0 release of JPA is very powerful indeed, is easy to use, and is very widely supported. It will probably mean the death of Ebean. Note that Play has added the following configuration feature into 2.0 (wasn't present in 1.1) - suggesting Play is moving towards fuller support for JPA from any provider. http://www.playframework.org/documentation/2.0/JavaJPA

    Once you do this, stop using play.db classes and com.avaje classes - I suggest you use 100% javax.persistence classes.



转载请标明出处:Eager fetch does not seem to join
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!