JPA EntityGraph,通过使用静态MetaModel可编程地创建PluralAttribute的子图

时间:2017-07-31 07:00:51

标签: hibernate jpa entitygraph

当我在实体下面时。

@Entity
class Article {
  @OneToMany
  Set<Comment> comments;
}

@Entity
class Comment {
  @ManyToOne
  User author;
}

使用EntityGraph和静态元模型创建一些视图规范类,如下所示。

class ArticleViewSpec {

  /**
   * fetch comments and each of comment's author.
   */
  public static final Function<EntityManager, EntityGraph<Article>> DETAIL = em -> {
    EntityGraph<Article> graph = em.createEntityGraph(Article.class);

    Subgraph<Comment> sgComment = graph.addSubgraph(Article_.comments);

    sgComment.addAttributeNodes(Comment_.author);

    return graph;
  };
}

但是上面的课程无法编译,因为期望的类型不是

Subgraph<Comment> sgComment = graph.addSubgraph(Article_.comments);

Subgraph<Set<Comment>> sgComment = graph.addSubgraph(Article_.comments);

当我们拥有扩展javax.persistence.metamodel.PluralAttribute的属性时会发生此问题。  (例如SetAttribute,ListAttribute)

这种行为显然来自API规范。 javax.persistence.EntityGraph#addSubgraph(javax.persistence.metamodel.Attribute<T,X>)

但是如何在这些情况下使用JPA静态MetaModel以可编程方式和类型安全地创建EntityGraph?

解决方法

/**
 * fetch comments and each of comment's author.
 */
public static final Function<EntityManager, EntityGraph<Article>> DETAIL = em -> {
    EntityGraph<Article> graph = em.createEntityGraph(Article.class);

    Subgraph<Comment> sgComment =
      graph.addSubgraph(Article_.comments.getName(), Comment.class);

    sgComment.addAttributeNodes(Comment_.author);

    return graph;
  };

1 个答案:

答案 0 :(得分:1)

我遇到了同样的问题,经过一些研究后我很确定这是JPA API 中的一个缺陷。

EclipseLink中的实现似乎做了正确的事情:

public <T> Subgraph<T> addSubgraph(Attribute<X, T> attribute) {
    Class type = attribute.getJavaType();
    if (attribute.isCollection()) {
        type = ((PluralAttribute) attribute).getBindableJavaType();
    }
    return addSubgraph(attribute.getName(), type);
}

注意当给出PluralAttribute时,实现如何违反界面中的声明:T的{​​{1}}为Attribute,该方法执行实际返回Collection<something>声明,而是Subgraph<Collection<something>>的实例。

对我而言,看起来API在这方面实际上已被打破,似乎没有人关心,因为可能没有多少人使用Subgraph<something> s 静态元模型,尽管这将是一件好事。

有人应该在某处创建一个问题,以便修复API的这一部分。

我对此问题的当前“修复”是一种自定义EntityGraph,它接受​​EntityGraphBuilderSingularAttribute<E,X>以允许PluralAttribute<E,?,X>的类型安全创建。基本上,我只是让我的EntityGraph表示树中的属性或节点,并通过类型安全的泛型方法将它们连接在一起。这样做的好处是可以在公共API下合并不同的for-cause-whatever EntityGraphElementEntityGraph接口,以便可以创建和使用SubGraph表示并将其重新用作子图在其他实体图中。

我的解决方案也可能应用于JPA API,它基本上只是拆分

EntityGraph

分为两种方法:

<T> Subgraph<T> addSubgraph(Attribute<X, T> attribute)

<F> EntityGraphElement<F> fetch(SingularAttribute<? super T, F> attr);

更新

使用一些泛型Voodoo,一个方法就足够了:

<F> EntityGraphElement<F> fetch(PluralAttribute<? super T, ?, F> attr);