英文:
Lazy loading not working with Specification
问题
已经迁移到Spring v2.1.2.RELEASE,并使用Hibernate版本5.3.7.FINAL。
我们在实体之间有一个@OneToOne双向关系,如下所示:
class Parent {
@OneToOne(fetch = FetchType.LAZY, mappedBy = "parent", optional = false)
@NotAudited
private Child child;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
class Child {
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id")
@MapsId
@NotNull
private Parent parent;
@Id
@Column(name = "indent_id", insertable = false, updatable = false)
private Integer parentId;
}
调用:
parentRepository.findByIdIn(Collections.singletonList(1));
会生成以下数据库调用:
Hibernate:
select parent0_.id as id1_19_ from parent parent0_ where parent0_.id in (?)
这个部分工作正常,现在考虑下面的用例:
public class Filter implements Specification<Parent> {
@Override
public Predicate toPredicate(Root<Indent> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
// TODO Auto-generated method stub
List<Integer> parentIdList = new ArrayList<>();
parentIdList.add(1);
ArrayList<Predicate> predicates = new ArrayList<>();
predicates.add(root.get("id").in(parentIdList));
return predicates.size() == 0 ? null
: criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
}
}
PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.Direction.DESC, "id");
Filter filter = new Filter();
Page<Indent> indentPage = indentRepository.findAll(filter, pageRequest);
会生成对Child实体的数据库调用:
Hibernate:
select parent0_.id as id1_19_ from parent parent0_ where parent0_.id in (?)
select child0_.parent_id as parent_i1_29_ from child child0_ where child0_.indent_id in (?)
有没有办法避免在这里对Child实体进行数据库调用?
英文:
I have migrated to spring v2.1.2.RELEASE and using hibernate version 5.3.7.FINAL
We have @OneToOne bi directional relationship between entity as follows
class Parent{
@OneToOne(fetch = FetchType.LAZY, mappedBy = "parent", optional = false)
@NotAudited
private Child child;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
class Child{
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id")
@MapsId
@NotNull
private Parent parent;
@Id
@Column(name = "indent_id", insertable = false, updatable = false)
private Integer parentId;
}
calling
parentRepository.findByIdIn(Collections.singletonList(1));
makes db call as:
Hibernate:
select parent0_.id as id1_19_ from parent parent0_ where parent0_.id in (?)
Which is working fine, now consider use case,
public class Filter implements Specification<Parent> {
@Override
public Predicate toPredicate(Root<Indent> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
// TODO Auto-generated method stub
List<Integer> parentIdList = new ArrayList<>();
parentIdList.add(1);
ArrayList<Predicate> predicates = new ArrayList<>();
predicates.add(root.get("id").in(parentIdList));
return predicates.size() == 0 ? null
: criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
}
}
PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.Direction.DESC, "id");
Filter filter = new Filter();
Page<Indent> indentPage = indentRepository.findAll(filter, pageRequest);
makes DB call to Child entity as well
Hibernate:
select parent0_.id as id1_19_ from parent parent0_ where parent0_.id in (?)
select child0_.parent_id as parent_i1_29_ from child child0_ where child0_.indent_id in (?)
Is there any way to avoid Db call to child entity here?
答案1
得分: 1
可以定义一个实体图来指定一个模式,该模式可以传递给查询,以确定要获取哪些属性。图中未包含的属性将被持久化提供程序视为延迟加载(LAZY)。
@Entity
@NamedEntityGraph(name = "only_id", attributeNodes = {@NamedAttributeNode("id")})
class Parent {
@OneToOne(fetch = FetchType.LAZY, mappedBy = "parent", optional = false)
@NotAudited
private Child child;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
JPA API:
EntityGraph entityGraph = entityManager.getEntityGraph("only_id");
// 定义你的查询
query.setHint("javax.persistence.fetchgraph", graph);
更多详情:https://docs.oracle.com/javaee/7/tutorial/persistence-entitygraphs002.htm
使用 Spring Data JPA:
public interface MyRepository extends JpaRepository<Parent, Integer> {
@EntityGraph(value = "only_id")
Parent findById(Integer id);
}
更多详情:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.entity-graph
JpaSpecificationExecutor:
public interface MyRepository extends JpaSpecificationExecutor<Parent> {
@Override
@EntityGraph(attributePaths = {"only_id"}, type = EntityGraphType.FETCH)
Parent findOne(Specification<Parent> spec);
}
更多详情:https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaSpecificationExecutor.html
英文:
You can define an entity graph to specify a pattern that can be passed to a query to determine which attributes you want to be fetched. Attributes that are not included in the graph will be treated as LAZY by persistence provider.
@Entity
@NamedEntityGraph(name = "only_id", attributeNodes={@NamedAttributeNode("id")})
class Parent{
@OneToOne(fetch = FetchType.LAZY, mappedBy = "parent", optional = false)
@NotAudited
private Child child;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
JPA API:
EntityGraph entityGraph = entityManager.getEntityGraph("only_idh");
// define your query
query.setHint("javax.persistence.fetchgraph",graph);
More details : https://docs.oracle.com/javaee/7/tutorial/persistence-entitygraphs002.htm
With Spring Data JPA
public interface MyRepository extends JpaRepository<Parent, Integer> {
@EntityGraph(value = "only id")
Parent findById(Integer id)
More details : https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.entity-graph
JpaSpecificationExecutor :
public interface MyRepository extends JpaSpecificationExecutor<Parent> {
@Override
@EntityGraph(attributePaths = {"only_id"}, type=EntityGraphType.FETCH)
Parent findByOne(Specification<Parent> spec);
}
More details : https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaSpecificationExecutor.html
答案2
得分: 0
JPA提供程序通常将fetch类型设置为Lazy作为提示,因此在您的情况下可能根本不考虑它。请查看以下内容:
fetch public abstract FetchType fetch(可选)定义字段或属性的值是否应该懒加载还是必须立即提取。EAGER策略是对持久性提供程序运行时的要求,必须立即提取值。LAZY策略是对持久性提供程序运行时的提示。如果未指定,默认为EAGER。默认值:EAGER
英文:
JPA provider usually takes fetch type Lazy as a hint, so may be in your case its not considering it at all. check below
> fetch public abstract FetchType fetch (Optional) Defines whether the
> value of the field or property should be lazily loaded or must be
> eagerly fetched. The EAGER strategy is a requirement on the
> persistence provider runtime that the value must be eagerly fetched.
> The LAZY strategy is a hint to the persistence provider runtime. If
> not specified, defaults to EAGER. Default: EAGER
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论