使用 Specification as Query 从 @Entity 以及关系 table 获取记录
Fetch Records from @Entity as well as relation table using Specification as Query
我正在查询来自与其他实体具有多对一关系的实体的数据。
使用 Specification 只能获取 Root 的 Record。但我也需要从关系实体中获取该列。
我是 Spring 新手,正在尝试构建 API。
查询根总是引用实体,那么如何使用规范中的自定义查询。
return new Specification<CallMessage>() {
private static final long serialVersionUID = 1L;
@Override
public Predicate toPredicate(Root<CallMessage> root,
CriteriaQuery<?> query, CriteriaBuilder cb)
{
List<Predicate> predicates = new ArrayList<>();
In<Long> inClause = cb.in(root.get("bed_address"));
inClause.value("XYZ");
predicates.add(inClause);
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
}
}
@Entity(name = "calls")
public class CallMessage implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@OneToMany(targetEntity = PresetModel.class, mappedBy = "id", orphanRemoval = false)
private Set<PresetModel> presetModels;
}
@Entity(name = "reports_preset_filter")
public class PresetModel extends AuditModel{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
private String preset_name;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name="call_id" ,nullable=false)
@OnDelete(action = OnDeleteAction.CASCADE)
@JsonIgnore
private CallMessage callMessage ;
}
虽然使用 JpaSpecificationExecutor 不能使用另一个查询来连接这两个表。有什么方法可以获取记录,例如-
call_message{
编号:1,
reports_preset_filter:[
]
}
我正在尝试使用多个谓词构建过滤器 API,为了放在这里,我已经削减了谓词列表以及实体的其他列。
发生的是 JPA @OneToMany
获取策略默认情况下是惰性的,这意味着引用字段只是 "empty" 代理,仅当您使用 getter.您可能希望保留此策略并仅为此查询获取字段。
一个优雅的解决方案是创建一个带有实体图的获取计划:
Entity graphs are templates for a particular Persistence query or operation. They are used when creating fetch plans, or groups of persistent fields that are retrieved at the same time[..] By default, entity fields or properties are fetched lazily. Developers specify fields or properties as part of a fetch plan, and the persistence provider will fetch them eagerly.
https://docs.oracle.com/javaee/7/tutorial/persistence-entitygraphs.htm
这是一个包含一些详细信息字段的主实体的代码示例:
@NamedEntityGraph(
name = "post-entity-graph-with-comment-users",
attributeNodes = {
@NamedAttributeNode("subject"),
@NamedAttributeNode(value = "comments", subgraph = "comments-subgraph"),
},
subgraphs = {
@NamedSubgraph(
name = "comments-subgraph",
attributeNodes = {
@NamedAttributeNode("user")
}
)
}
)
@Entity
public class Post {
@Id
private Long id;
private String subject;
@OneToMany(mappedBy = "post")
private List<Comment> comments;
}
@Entity
public class Comment {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn
private User user;
//...
}
然后你可以有一个 SimpleJpaRepository
子类覆盖
@Override
public List<T> findAll(Specification<T> spec, Sort sort, EntityGraph.EntityGraphType entityGraphType, String entityGraphName) {
TypedQuery<T> query = getQuery(spec, sort);
query.setHint(entityGraphType.getKey(), em.getEntityGraph(entityGraphName));
return query.getResultList();
}
因此 运行 一个 Specification
也加载与评论相关的用户:
List<Post> results = myRepository.findAll(mySpecification, EntityGraph.EntityGraphType.LOAD, "post-entity-graph-with-comment-users");
我正在查询来自与其他实体具有多对一关系的实体的数据。 使用 Specification 只能获取 Root 的 Record。但我也需要从关系实体中获取该列。
我是 Spring 新手,正在尝试构建 API。
查询根总是引用实体,那么如何使用规范中的自定义查询。
return new Specification<CallMessage>() {
private static final long serialVersionUID = 1L;
@Override
public Predicate toPredicate(Root<CallMessage> root,
CriteriaQuery<?> query, CriteriaBuilder cb)
{
List<Predicate> predicates = new ArrayList<>();
In<Long> inClause = cb.in(root.get("bed_address"));
inClause.value("XYZ");
predicates.add(inClause);
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
}
}
@Entity(name = "calls")
public class CallMessage implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@OneToMany(targetEntity = PresetModel.class, mappedBy = "id", orphanRemoval = false)
private Set<PresetModel> presetModels;
}
@Entity(name = "reports_preset_filter")
public class PresetModel extends AuditModel{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
private String preset_name;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name="call_id" ,nullable=false)
@OnDelete(action = OnDeleteAction.CASCADE)
@JsonIgnore
private CallMessage callMessage ;
}
虽然使用 JpaSpecificationExecutor 不能使用另一个查询来连接这两个表。有什么方法可以获取记录,例如- call_message{ 编号:1, reports_preset_filter:[ ] }
我正在尝试使用多个谓词构建过滤器 API,为了放在这里,我已经削减了谓词列表以及实体的其他列。
发生的是 JPA @OneToMany
获取策略默认情况下是惰性的,这意味着引用字段只是 "empty" 代理,仅当您使用 getter.您可能希望保留此策略并仅为此查询获取字段。
一个优雅的解决方案是创建一个带有实体图的获取计划:
Entity graphs are templates for a particular Persistence query or operation. They are used when creating fetch plans, or groups of persistent fields that are retrieved at the same time[..] By default, entity fields or properties are fetched lazily. Developers specify fields or properties as part of a fetch plan, and the persistence provider will fetch them eagerly.
https://docs.oracle.com/javaee/7/tutorial/persistence-entitygraphs.htm
这是一个包含一些详细信息字段的主实体的代码示例:
@NamedEntityGraph(
name = "post-entity-graph-with-comment-users",
attributeNodes = {
@NamedAttributeNode("subject"),
@NamedAttributeNode(value = "comments", subgraph = "comments-subgraph"),
},
subgraphs = {
@NamedSubgraph(
name = "comments-subgraph",
attributeNodes = {
@NamedAttributeNode("user")
}
)
}
)
@Entity
public class Post {
@Id
private Long id;
private String subject;
@OneToMany(mappedBy = "post")
private List<Comment> comments;
}
@Entity
public class Comment {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn
private User user;
//...
}
然后你可以有一个 SimpleJpaRepository
子类覆盖
@Override
public List<T> findAll(Specification<T> spec, Sort sort, EntityGraph.EntityGraphType entityGraphType, String entityGraphName) {
TypedQuery<T> query = getQuery(spec, sort);
query.setHint(entityGraphType.getKey(), em.getEntityGraph(entityGraphName));
return query.getResultList();
}
因此 运行 一个 Specification
也加载与评论相关的用户:
List<Post> results = myRepository.findAll(mySpecification, EntityGraph.EntityGraphType.LOAD, "post-entity-graph-with-comment-users");