5

当我有以下实体时。

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

1 回答 1

4

我遇到了同样的问题,经过一些研究,我很确定这是 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请注意,当给定a 时,实现如何违反接口的声明:T如果Attribute是 a Collection<something>,该方法实际上并没有返回Subgraph<Collection<something>>声明的 a 而是一个实例Subgraph<something>

在我看来,API 在这方面实际上被破坏了,似乎没有人关心,因为可能没有多少人使用EntityGraphs静态元模型,尽管这样做是件好事。

有人应该在某处创建问题以修复 API 的那部分。

我目前对该问题的“修复”是一种EntityGraphBuilder接受SingularAttribute<E,X>PluralAttribute<E,?,X>允许类型安全地创建EntityGraphs 的自定义。基本上,我只是让我EntityGraphElement的 s 代表树中的一个属性或节点,并通过类型安全的泛型方法将它们连接在一起。这还具有将不同的原因EntityGraphSubGraph接口合并到一个通用 API 下的好处,以便EntityGraph可以创建和使用表示,并在其他实体图中作为子图重新使用。

我的解决方案也可能适用于 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);
于 2018-03-16T16:31:14.593 回答