当前位置: 首页 > 知识库问答 >
问题:

在子实体与@ManyToOne相关的情况下,如何在JPA eclipselink中获取连接嵌套实体

陶高峯
2023-03-14

我想在单个查询中获取多个实体,因为n1查询持续时间太长。例如,SQL join查询在数据库上持续5秒,但由于N 1抓取,elcipselink持久性抓取持续50-80秒。我发现只要@ManyToOne关系被实现,LEFT JOIN 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; 
}

我就是这样取的。我已经尝试了以下所有组合,但每个组合都会对SituationData中的每一行(对象)进行查询,或者在某些情况下对每个连接的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();

共有1个答案

段溪叠
2023-03-14

由于您没有明确声明正在使用的Eclipse Link版本,我将假设版本2.6。

根据EclipseLink官方文档,EclipseLink。LEFT_FETCH不是受支持的查询提示。您可能正在尝试使用eclipselink。加入fetch或eclipselink。左连接获取,如本文所述。

使用此提示的正确方法如下:

String sQuery = "SELECT ds FROM DatexSituationData ds";      

EntityManager em = emf.getInstance().getFactory().createEntityManager();
TypedQuery q = em.createQuery(sQuery, DatexSituationData.class);
q.setHint("eclipselink.join-fetch", "ds.situationRecords");
q.setHint("eclipselink.join-fetch", "ds.situationLocation");
// ...

lResult = q.getResultList();

另一种方法是批量抓取。

这将起到以下作用:

//...
em
.createQuery("SELECT ds FROM DatexSituationData ds")
.setHint("eclipselink.batch", "ds.situationRecords")
//...
.setHint("eclipselink.batch.type", "IN")
.setHint("eclipselink.batch_size", "1000");
//...

您可能会测试这两种方法并收集一些指标;然后决定哪一个更适合您的DB模式和使用模式(在性能方面)。

 类似资料:
  • 问题内容: 但是,首选解决方案(属性访问)在我的情况下不起作用(我缺少列异常-为什么?) 该模型如下所示:实体和。表含有列是的表,以便它是典型的关系。 现在的问题是,如果我取的实体,我需要有机会获得价值(亦称的实体),而不取实体。我怎样才能做到这一点? 我使用的映射如下所示: 我想做的是调用而无需从DB中额外获取实体。 根据我上面提到的答案,如果我将注释从字段移到getter(在实体上,我对吗?)

  • 问题内容: 我有两个实体: 保存首选项时,我具有accountId,但没有Account实体。在这种情况下,如何保存首选项? 加载帐户实体并在首选项上进行设置?对我来说,这似乎是对数据库的错误旅行。 是否具有一个可持久保存的accountId字段并使Account字段为只读?同时拥有一个accountId字段和一个Account字段似乎多余吗? 使用NamedQuery保留首选项?我希望只是通用地

  • 问题内容: 我有以下用于测试的类: 为了进行测试,我想通过一次SaveChanges调用插入一家公司和该公司的一名员工,如下所示: 即使我没有使用导航属性,而是通过Id建立了联系,但这种方式还是神秘地起作用了- 员工用正确的外键保存了公司的外键,该公司的外键从0更新为实际值,这使我走了出去!一些隐藏的C#功能? 然后,我决定添加更多代码,上面的代码段中对此进行了注释,使其插入了2个Company实

  • 当连接到rabbitmq队列服务器失败时,我正在尝试实现重新连接机制。此代码仅用于消费消息,下面是我的代码(channel Init函数负责初始化消费者并绑定到队列)。 连接失败时,我成功收到提示“[AMQP] 重新连接”,但在该队列未重新连接后,控制台日志中没有其他提示。 请帮忙。

  • 经过多次尝试,我来到这里,根据文档: Firestore为离线功能提供现成的支持。在读取和写入数据时,Firestore使用一个本地数据库,该数据库会自动与服务器同步。当用户脱机时,云Firestore功能将继续,当他们重新连接时,将自动处理数据迁移。 所以,我在中编写了一些代码 工作很好。 但是当我关闭我的互联网连接,并从最近的应用程序中删除应用程序,然后返回我的应用程序时,它在离线状态下不起作

  • 我有一个简单的问题,但似乎找不到解决的办法。我使用的是EntityFramework核心版本2.0.1,希望在默认情况下加载所有实体。 示例: 但当我加载订单实体时,相关实体Customer及其内部地址为null 我所尝试的: 尝试升级到版本2.1并使用LazyLoadingProxies设置为false 这只是一个例子,我有多个嵌套级别的实体,我想在通用存储库中加载嵌套的相关数据,因此不能使用I