当我有以下实体时。

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

@Entity
class Comment {
  @ManyToOne
  User author;
}

并使用EntityGraph和静态元模型创建一些 View 规范类,如下所示。
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;
  };

最佳答案

我遇到了同样的问题,经过研究后,我确定这是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时,实现是如何违反接口(interface)的声明的:TAttributeCollection<something>时,该方法实际上不返回声明的Subgraph<Collection<something>>,而是返回Subgraph<something>的实例。

在我看来,该API实际上在这方面已被破坏,而且似乎没人在乎,因为可能没有多少人使用EntityGraph和静态元模型,尽管这样做是一件好事。

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

我当前针对该问题的“解决方案”是一种自定义的EntityGraphBuilder,它接受SingularAttribute<E,X>PluralAttribute<E,?,X>以允许对EntityGraph进行类型安全的创建。基本上,我只是用EntityGraphElement表示树中的属性或节点,然后通过类型安全的泛型方法将它们插入在一起。这还具有在通用API下合并不同原因的EntityGraphSubGraph接口(interface)的优点,以便可以创建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);

更新:

使用一些通用伏都教徒,一种方法就足够了:
<F, A extends Attribute<? super T, ?> & Bindable<F>> EntityGraphElement<F> fetch(A attribute);

关于hibernate - JPA EntityGraph,使用静态MetaModel可编程地创建PluralAttribute的子图,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45409305/

10-10 08:01