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
时实现如何违反接口的声明:由于 Attribute
的 T
是 Collection<something>
,该方法会 不是 实际上 return 声明的 Subgraph<Collection<something>>
而是 Subgraph<something>
的一个实例。
对我来说,API 似乎在这方面实际上被打破了,而且似乎没有人关心,因为可能没有多少人使用 EntityGraph
s and 静态元模型,虽然这是一件好事。
有人应该在某个地方创建一个问题来修复 API 的那一部分。
我当前的 'fix' 问题是一种自定义 EntityGraphBuilder
,它接受 SingularAttribute<E,X>
和 PluralAttribute<E,?,X>
以允许类型 safe-ish 创建 EntityGraph
秒。基本上,我只有 EntityGraphElement
s 表示树中的属性或节点,并通过 type-safe 通用方法将它们连接在一起。这也有利于在公共 API 下合并不同的 for-whatever-reason EntityGraph
和 SubGraph
接口,以便可以创建和使用 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);
当我有以下实体时。
@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
时实现如何违反接口的声明:由于 Attribute
的 T
是 Collection<something>
,该方法会 不是 实际上 return 声明的 Subgraph<Collection<something>>
而是 Subgraph<something>
的一个实例。
对我来说,API 似乎在这方面实际上被打破了,而且似乎没有人关心,因为可能没有多少人使用 EntityGraph
s and 静态元模型,虽然这是一件好事。
有人应该在某个地方创建一个问题来修复 API 的那一部分。
我当前的 'fix' 问题是一种自定义 EntityGraphBuilder
,它接受 SingularAttribute<E,X>
和 PluralAttribute<E,?,X>
以允许类型 safe-ish 创建 EntityGraph
秒。基本上,我只有 EntityGraphElement
s 表示树中的属性或节点,并通过 type-safe 通用方法将它们连接在一起。这也有利于在公共 API 下合并不同的 for-whatever-reason EntityGraph
和 SubGraph
接口,以便可以创建和使用 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);