当我有以下实体时。
@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)的声明的:T
的Attribute
为Collection<something>
时,该方法实际上不返回声明的Subgraph<Collection<something>>
,而是返回Subgraph<something>
的实例。在我看来,该API实际上在这方面已被破坏,而且似乎没人在乎,因为可能没有多少人使用
EntityGraph
和静态元模型,尽管这样做是一件好事。有人应该在某个地方创建问题以修复API的该部分。
我当前针对该问题的“解决方案”是一种自定义的
EntityGraphBuilder
,它接受SingularAttribute<E,X>
和PluralAttribute<E,?,X>
以允许对EntityGraph
进行类型安全的创建。基本上,我只是用EntityGraphElement
表示树中的属性或节点,然后通过类型安全的泛型方法将它们插入在一起。这还具有在通用API下合并不同原因的EntityGraph
和SubGraph
接口(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/