JPA EntityGraph,使用静态元模型以编程方式创建 PluralAttribute 的子图

JPA EntityGraph, create subgraph of PluralAttribute programmably by using static MetaModel

当我有以下实体时。

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

@Entity
class Comment {
  @ManyToOne
  User author;
}

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

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;
  };
}

但是上面的class编译不了,因为期望的类型不是

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 静态元模型以可编程方式安全地创建 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;
  };

我 运行 遇到了同样的问题,在做了一些研究之后,我很确定这是 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 时实现如何违反接口的声明:由于 AttributeTCollection<something>,该方法会 不是 实际上 return 声明的 Subgraph<Collection<something>> 而是 Subgraph<something> 的一个实例。

对我来说,API 似乎在这方面实际上被打破了,而且似乎没有人关心,因为可能没有多少人使用 EntityGraphs and 静态元模型,虽然这是一件好事。

有人应该在某个地方创建一个问题来修复 API 的那一部分。

我当前的 'fix' 问题是一种自定义 EntityGraphBuilder,它接受 SingularAttribute<E,X>PluralAttribute<E,?,X> 以允许类型 safe-ish 创建 EntityGraph秒。基本上,我只有 EntityGraphElements 表示树中的属性或节点,并通过 type-safe 通用方法将它们连接在一起。这也有利于在公共 API 下合并不同的 for-whatever-reason EntityGraphSubGraph 接口,以便可以创建和使用 EntityGraph 表示并且 re-used作为其他实体图中的子图。

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

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

分为两种方法:

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

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

更新:

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

<F, A extends Attribute<? super T, ?> & Bindable<F>> EntityGraphElement<F> fetch(A attribute);