3

我正在使用带有 Java 的 play 2.0.4。我正在尝试从 play 提供的内存数据库中保存和检索一个值(Ebean 是底层 JPA 实现)。这是一些示例代码:

@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();
}

}

在 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>

问题是当我在控制器中执行 User.all() 并将其发送到视图时,未加载 user.role,即 @usr.role.name 为空白。也不例外。我已经设置了 SQL 调试,并且我已经验证了 Role 表的外键保存在 User 表中。当我在 User.all() 方法(参见 SOP2)中打印角色名称时,会触发一个查询并打印角色名称。它也显示在视图上。

我知道,默认情况下,角色将被延迟加载,并且模板中无法使用 PersistenceContext 来加载与用户关联的角色。但是,不应该急切地获取对象的所有相关实体吗?我对 Play 和 JPA 还很陌生,当我加载某些东西时,我不知道如何在不通过每个关联实体的情况下让它工作。有什么我想念的吗?

在相关的说明中,如果我必须使用延迟获取,我如何确保在获取用户时 user.role 对视图可用?

4

1 回答 1

4

Ebean 是底层的 JPA 实现

Ebean 不是 JPA 实现。Ebean 与 JPA 标准有一点共同点。它看起来有点相似,因为它的注解看起来与 JPA 的相似。

问题的原因:Ebean 不支持 @ManyToMany 注释上的 fetch=... 属性。

2个解决方案:

  1. play.db.ebean.Model.Finder<I,T>从注释中删除 fetch=... ,而是在对象(实现com.avaje.ebean.Query<T>)或 com.avaje.ebean.Ebean 对象上使用 fetch() 方法。

    问题是这里有两个独立的持久库(play.db.ebean 和 com.avaje.ebean),它们之间的集成是一个挑战和问题。
    例如 play.db.ebean.Model.Finder.fetch() 方法返回com.avaje.ebean.Query<T> 而不是 play.db.ebean.Model.Finder - 我发现它没有帮助,因为它让你远离 play API 模型助手。显然在调用 fetch() 之后,您不能再使用 Model.Finder 方法 - 那时没有太多的“帮助”类。
    老实说,我不认为 fetch 功能是 Play API 中的一流功能 - 最好遵循 Avaje API。

    在 Avaje API 中使用 fetch() 的两个示例:

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

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

    注意:Ebean 的最后一次发布/更新(其他错误修复)是 2010 年 11 月 6 日 - 整整 2 年前。Ebean的吸收率非常低。

  2. 切换到在 Play 中使用 JPA 2.0 实现。JPA 2.0 版本确实非常强大,易于使用,并且得到了非常广泛的支持。这可能意味着 Ebean 的死亡。请注意,Play 在 2.0 中添加了以下配置功能(在 1.1 中不存在)——这表明 Play 正在朝着任何提供商对 JPA 的更全面支持迈进。 http://www.playframework.org/documentation/2.0/JavaJPA

    一旦你这样做了,停止使用 play.db 类和 com.avaje 类——我建议你使用 100% javax.persistence 类。

于 2012-11-02T08:42:27.083 回答