JPA 惰性 OneToOne 关系在不应该加载或查询实体时被获取?为什么?
JPA lazy OneToOne relation is fetched when loading or querying an entity when it shouldn't? Why?
鉴于这两个实体具有 OneToOne 关系(A 作为拥有方持有 B 实体 ID):
@Entity
@Table(name="A")
public class AEntity{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
...
@OneToOne(optional = true, cascade = CascadeType.ALL)
@JoinColumn(name = "bId")
private BEntity b;
}
@Entity
@Table(name="B")
public class BEntity{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@OneToOne(mappedBy = "b", cascade = CascadeType.ALL, optional = true, fetch = FetchType.LAZY)
private AEntity a;
...
@Temporal(TemporalType.TIMESTAMP)
@Column(nullable = false)
protected Date someDate;
}
我使用条件查询来获取给定日期内的所有 B 实体:
public class BSpecification {
public static Specification<BEntity> filter(BFilter filter) {
return new Specification<BEntity>() {
@Override
public Predicate toPredicate(Root<BEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> predicates = new ArrayList<Predicate>();
if(filter.getDateFrom() != null){
predicates.add(cb.greaterThanOrEqualTo(cb.function("date", Date.class, root.get(BEntity_.someDate)),
filter.getDateFrom()));
}
if(filter.getDateTo() != null){
predicates.add(cb.lessThanOrEqualTo(cb.function("date", Date.class, root.get(BEntity_.someDate)),
filter.getDateTo()));
}
if(predicates.size()==0){
return null;
}else{
return cb.and(predicates.toArray(new Predicate[0]));
}
}
};
}
}
查询是用 bRepository.findAll(BSpecification.filter(filter));
执行的,我看到在根据日期获取 BEntities 之后...
select
b0_.id as id1_7_,
b0_.some_date as some_date_cr2_7_,
from
b b0_
where
date(b0_.some_date)>=?
and date(b0_.some_date)<=?
...还有一个获取一对一延迟相关的AEntity:
select
a0_.id as id1_9_2_,
a0_.b_id as b14_9_2_,
from
a a0_
where
a0_.b_id=?
由于性能原因,我需要阻止加载 AEntities,为什么这个条件会获取它们?
更新:为了简化问题我刚刚加载了一个 BEntities bRepository.findOne(bId)
并且发生了同样的事情。所以这与标准无关,而与映射有关。怎么了?
这才是对我有用的,被接受的参考答案没有:
只需更新我的 Bentity 即可实现 FieldHandler,仅此而已:
@Entity
@Table(name="B")
public class BEntity implements FieldHandled{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@OneToOne(mappedBy = "b", cascade = CascadeType.ALL, optional = true,
fetch = FetchType.LAZY)
private AEntity a;
...
@Temporal(TemporalType.TIMESTAMP)
@Column(nullable = false)
protected Date someDate;
public AEntity getA() {
if (fieldHandler != null) {
return (AEntity) fieldHandler.readObject(this, "a", a);
}
return notificacion;
}
public void setA(AEntity a) {
if (fieldHandler != null) {
this.a = (AEntity) fieldHandler.writeObject(this, "a", this.a,
a);
return;
}
this.a = a;
}
}
鉴于这两个实体具有 OneToOne 关系(A 作为拥有方持有 B 实体 ID):
@Entity
@Table(name="A")
public class AEntity{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
...
@OneToOne(optional = true, cascade = CascadeType.ALL)
@JoinColumn(name = "bId")
private BEntity b;
}
@Entity
@Table(name="B")
public class BEntity{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@OneToOne(mappedBy = "b", cascade = CascadeType.ALL, optional = true, fetch = FetchType.LAZY)
private AEntity a;
...
@Temporal(TemporalType.TIMESTAMP)
@Column(nullable = false)
protected Date someDate;
}
我使用条件查询来获取给定日期内的所有 B 实体:
public class BSpecification {
public static Specification<BEntity> filter(BFilter filter) {
return new Specification<BEntity>() {
@Override
public Predicate toPredicate(Root<BEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> predicates = new ArrayList<Predicate>();
if(filter.getDateFrom() != null){
predicates.add(cb.greaterThanOrEqualTo(cb.function("date", Date.class, root.get(BEntity_.someDate)),
filter.getDateFrom()));
}
if(filter.getDateTo() != null){
predicates.add(cb.lessThanOrEqualTo(cb.function("date", Date.class, root.get(BEntity_.someDate)),
filter.getDateTo()));
}
if(predicates.size()==0){
return null;
}else{
return cb.and(predicates.toArray(new Predicate[0]));
}
}
};
}
}
查询是用 bRepository.findAll(BSpecification.filter(filter));
执行的,我看到在根据日期获取 BEntities 之后...
select
b0_.id as id1_7_,
b0_.some_date as some_date_cr2_7_,
from
b b0_
where
date(b0_.some_date)>=?
and date(b0_.some_date)<=?
...还有一个获取一对一延迟相关的AEntity:
select
a0_.id as id1_9_2_,
a0_.b_id as b14_9_2_,
from
a a0_
where
a0_.b_id=?
由于性能原因,我需要阻止加载 AEntities,为什么这个条件会获取它们?
更新:为了简化问题我刚刚加载了一个 BEntities bRepository.findOne(bId)
并且发生了同样的事情。所以这与标准无关,而与映射有关。怎么了?
这才是对我有用的,被接受的参考答案没有:
只需更新我的 Bentity 即可实现 FieldHandler,仅此而已:
@Entity
@Table(name="B")
public class BEntity implements FieldHandled{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@OneToOne(mappedBy = "b", cascade = CascadeType.ALL, optional = true,
fetch = FetchType.LAZY)
private AEntity a;
...
@Temporal(TemporalType.TIMESTAMP)
@Column(nullable = false)
protected Date someDate;
public AEntity getA() {
if (fieldHandler != null) {
return (AEntity) fieldHandler.readObject(this, "a", a);
}
return notificacion;
}
public void setA(AEntity a) {
if (fieldHandler != null) {
this.a = (AEntity) fieldHandler.writeObject(this, "a", this.a,
a);
return;
}
this.a = a;
}
}