如何获取JPA-ECLIPSELINK中的嵌套实体,以防属于@manytoone
我有多个我想在单个查询中获取的实体,因为n+1查询持续时间太长。 例如,SQL加入查询持续5秒在DB上,但是由于n+1提取,Elcipselink持久性提取持续50-80秒。 我发现,在实现@manytoone关系后,左加入Fetch无法正常工作。 有人知道解决此案的解决方案吗?
请在下面找到简化的实体。
@Entity
@Table(name="SITUATION_DATA")
@NamedQuery(name="SituationData.findAll", query="SELECT s FROM SituationData s")
public class DatexSituationData implements Serializable {
private static final long serialVersionUID = 1L;
//bi-directional many-to-one association to SituationRecord
@OneToMany(mappedBy="datexSituationData", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
@JoinFetch(value=JoinFetchType.OUTER)
private List<SituationRecord> situationRecords;
}
@Entity
@Table(name="SituationRecord")
@NamedQuery(name="SituationRecord.findAll", query="SELECT s FROM SituationRecord s")
public class SituationRecord implements Serializable {
private static final long serialVersionUID = 1L;
@OneToMany(mappedBy="situationRecord", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
@JoinFetch(value=JoinFetchType.OUTER)
private List<SituationRecordComment> situationRecordComment;
@OneToMany(mappedBy="situationRecord", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
@JoinFetch(value=JoinFetchType.OUTER)
private List<SituationRecordTypeElement> situationRecordTypeElements;
//bi-directional many-to-one association to SituationLocation
@ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
@JoinFetch(value=JoinFetchType.OUTER)
@JoinColumn(name="ID_LOKACIJE")
private SituationLocation situationLocation;
//bi-directional many-to-one association to DatexSituationData
@ManyToOne()
@JoinColumns({
@JoinColumn(name="SITUATION_ID", referencedColumnName="ID", nullable=false),
@JoinColumn(name="SITUATION_VERSION", referencedColumnName="VERSION", nullable=false)
})
private DatexSituationData datexSituationData;
}
@Entity
@Table(name="SITUATION_LOCATIONS")
@NamedQuery(name="SituationLocation.findAll", query="SELECT s FROM SituationLocation s")
public class SituationLocation implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="situation_location_seq")
@SequenceGenerator(name="situation_location_seq", sequenceName="SEQ_SITUATION_LOCATION", allocationSize=1)
@Column(name="ID_LOKACIJE", unique=true, nullable=false)
private long idLokacije;
//bi-directional many-to-one association to SituationRecord
@OneToMany(mappedBy="situationLocation", cascade = CascadeType.PERSIST)
private List<SituationRecord> situationRecords;
}
这就是我的获取方式。 我已经尝试了以下所有组合,但是每个组合都会对centerdata中的每一行(对象)进行查询,或者在某些情况下对每种加入的情况data coindata加入centaineRecord。
String sQuery =
//"select * from SITUATION_DATA t";
//"SELECT * FROM (select t.*, rank() over(partition by t.id order by version desc) rnk from SITUATION_DATA t) where rnk = 1";
"SELECT ds FROM SituationData ds LEFT JOIN FETCH ds.situationRecords sr LEFT JOIN FETCH sr.situationLocation sl LEFT JOIN FETCH sr.situationRecordTypeElements sre LEFT JOIN FETCH sr.situationRecordComment src";
EntityManager em = Emf.getInstance().getFactory().createEntityManager();
//Query q = em.createNativeQuery(sQuery, DatexSituationData.class);
Query q = em.createQuery(sQuery, DatexSituationData.class);
// q.setHint("eclipselink.LEFT_FETCH", "t.situationRecords.situationRecordComment");
q.setHint("eclipselink.LEFT_FETCH", "ds.sr.sl");
q.setHint("eclipselink.LEFT_FETCH", "ds.sr.sre");
q.setHint("eclipselink.LEFT_FETCH", "ds.sr.src");
// q.setHint("eclipselink.JDBC_FETCH_SIZE", "100");
lResult = q.getResultList();
I have multiple entities that i want to fetch in single query, because N+1 queries last too long.
For example SQL join query lasts 5 seconds on DB, but elcipselink persistence fetching lasts 50-80 seconds due to N+1 fetching.
I found out that LEFT JOIN FETCH is not working as soon as @ManyToOne relation is implemented.
Does anyone know solution to LEFT JOIN FETCH for this case?
Please find below simplified entities.
@Entity
@Table(name="SITUATION_DATA")
@NamedQuery(name="SituationData.findAll", query="SELECT s FROM SituationData s")
public class DatexSituationData implements Serializable {
private static final long serialVersionUID = 1L;
//bi-directional many-to-one association to SituationRecord
@OneToMany(mappedBy="datexSituationData", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
@JoinFetch(value=JoinFetchType.OUTER)
private List<SituationRecord> situationRecords;
}
@Entity
@Table(name="SituationRecord")
@NamedQuery(name="SituationRecord.findAll", query="SELECT s FROM SituationRecord s")
public class SituationRecord implements Serializable {
private static final long serialVersionUID = 1L;
@OneToMany(mappedBy="situationRecord", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
@JoinFetch(value=JoinFetchType.OUTER)
private List<SituationRecordComment> situationRecordComment;
@OneToMany(mappedBy="situationRecord", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
@JoinFetch(value=JoinFetchType.OUTER)
private List<SituationRecordTypeElement> situationRecordTypeElements;
//bi-directional many-to-one association to SituationLocation
@ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
@JoinFetch(value=JoinFetchType.OUTER)
@JoinColumn(name="ID_LOKACIJE")
private SituationLocation situationLocation;
//bi-directional many-to-one association to DatexSituationData
@ManyToOne()
@JoinColumns({
@JoinColumn(name="SITUATION_ID", referencedColumnName="ID", nullable=false),
@JoinColumn(name="SITUATION_VERSION", referencedColumnName="VERSION", nullable=false)
})
private DatexSituationData datexSituationData;
}
@Entity
@Table(name="SITUATION_LOCATIONS")
@NamedQuery(name="SituationLocation.findAll", query="SELECT s FROM SituationLocation s")
public class SituationLocation implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="situation_location_seq")
@SequenceGenerator(name="situation_location_seq", sequenceName="SEQ_SITUATION_LOCATION", allocationSize=1)
@Column(name="ID_LOKACIJE", unique=true, nullable=false)
private long idLokacije;
//bi-directional many-to-one association to SituationRecord
@OneToMany(mappedBy="situationLocation", cascade = CascadeType.PERSIST)
private List<SituationRecord> situationRecords;
}
This is how i fetch it.
I have tried all of the below combinations, but every combinations makes query for each row (object) in SituationData, or in some cases for each joined SituationData join SituationRecord.
String sQuery =
//"select * from SITUATION_DATA t";
//"SELECT * FROM (select t.*, rank() over(partition by t.id order by version desc) rnk from SITUATION_DATA t) where rnk = 1";
"SELECT ds FROM SituationData ds LEFT JOIN FETCH ds.situationRecords sr LEFT JOIN FETCH sr.situationLocation sl LEFT JOIN FETCH sr.situationRecordTypeElements sre LEFT JOIN FETCH sr.situationRecordComment src";
EntityManager em = Emf.getInstance().getFactory().createEntityManager();
//Query q = em.createNativeQuery(sQuery, DatexSituationData.class);
Query q = em.createQuery(sQuery, DatexSituationData.class);
// q.setHint("eclipselink.LEFT_FETCH", "t.situationRecords.situationRecordComment");
q.setHint("eclipselink.LEFT_FETCH", "ds.sr.sl");
q.setHint("eclipselink.LEFT_FETCH", "ds.sr.sre");
q.setHint("eclipselink.LEFT_FETCH", "ds.sr.src");
// q.setHint("eclipselink.JDBC_FETCH_SIZE", "100");
lResult = q.getResultList();
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
由于您没有明确使用Eclipselink版本,因此我只假设版本2.6。
按照 eclipselink.left_fetch 不是受支持的查询提示。您可能正在尝试使用
eclipselink.join-fetch
或eclipselink.left-join-fetch
as 。使用此提示的正确方法沿着:
另一种方法是批次提取。
这将起作用:
您可能会测试两种方法并收集一些指标;然后,确定哪个对DB模式和使用模式更好(在性能方面)。
Since you are not explicitly state EclipseLink version being used, I'll just assume version 2.6.
As per the official EclipseLink documentation,
eclipselink.LEFT_FETCH
is not a supported query hint. You are probably trying to useeclipselink.join-fetch
oreclipselink.left-join-fetch
as documented here.The proper way to use this hint is along the lines of:
Another approach would be batch fetching.
This would work as:
You would probably test both approaches and gather some metrics; then decide which one works better (in terms of performance) for your DB schema and usage patterns.