java – 在同一实体上JOIN FETCH之后的Hibernate额外查询
我试图通过使用此查询来查询大量的实体,尽管Hibernate:
"Select * " + " From Dossier as dossier" + " LEFT JOIN FETCH dossier.candidat as candidat " + " LEFT JOIN FETCH candidat.roles as role " + " LEFT JOIN FETCH dossier.infoPerso as infoPerso " + " LEFT JOIN FETCH dossier.etablissementOrigine as etablissementOrigine " + " LEFT JOIN FETCH etablissementOrigine.filieres as filieres " + " LEFT OUTER JOIN FETCH etablissementOrigine.ville as villeOrigine " + " LEFT JOIN FETCH dossier.etatDossier as etatDossier " + " LEFT OUTER JOIN FETCH infoPerso.fichierCNIRecto as fichierCNIRecto " + " LEFT OUTER JOIN FETCH fichierCNIRecto.type " + " LEFT OUTER JOIN FETCH infoPerso.fichierCNIVerso as fichierCNIVerso " + " LEFT OUTER JOIN FETCH fichierCNIVerso.type " + " LEFT OUTER JOIN FETCH infoPerso.fichierCV as fichierCV " + " LEFT OUTER JOIN FETCH fichierCV.type " + " LEFT OUTER JOIN FETCH infoPerso.fichierJAPD as fichierJAPD " + " LEFT OUTER JOIN FETCH fichierJAPD.type " + " LEFT OUTER JOIN FETCH infoPerso.fichierCNIVerso as fichierCNIVerso " + " LEFT OUTER JOIN FETCH fichierCNIVerso.type " + " LEFT OUTER JOIN FETCH infoPerso.situationFamilliale as situation " dossiers = getEntityManager() .createQuery(sql,Dossier.class) .getResultList(); 我可以看到hibernate在做第一个大的本机SQL查询.但就在那之后,Hibernate为每一行生成了1个以上的查询来加载DOssier,我不知道为什么,Dossier已经是fetchs元素的一部分…… /* load org.ema.ecandidature.dossier.Dossier */ select dossier0_.id as id1_61_0_,dossier0_.version as version2_61_0_,dossier0_.valid as valid3_61_0_,dossier0_.validSecretariat as validSec4_61_0_,dossier0_.candidat_id as candidat7_17_0_,dossier0_.casParticulier as casParti1_17_0_,dossier0_.dateInscription as dateInsc2_17_0_,dossier0_.dateSoumission as dateSoum3_17_0_,dossier0_.entreprise_id as entrepri8_17_0_,dossier0_.etablissementOrigine_id as etabliss9_17_0_,dossier0_.etatDossier_id as etatDos10_17_0_,dossier0_.infoPaiement_id as infoPai11_17_0_,dossier0_.infoPerso_id as infoPer12_17_0_,dossier0_.listCursusAcademique_id as listCur13_17_0_,dossier0_.listDocumentsSupplementaires_id as listDoc14_17_0_,dossier0_.listExpEntreprise_id as listExp15_17_0_,dossier0_.listFormations_id as listFor16_17_0_,dossier0_.listLangues_id as listLan17_17_0_,dossier0_.listReferents_id as listRef18_17_0_,dossier0_.listSejourEtranger_id as listSej19_17_0_,dossier0_.motivationCentreInteret_id as motivat20_17_0_,dossier0_.secretariatChangeDate as secretar4_17_0_,dossier0_.secretariatChangeDateBackup as secretar5_17_0_,dossier0_.validationCommentaire as validati6_17_0_ from Dossier dossier0_ where dossier0_.candidat_id=? Dossier.class: @Entity @BatchSize(size=100) public class Dossier extends ValidableEntity { /** The Constant serialVersionUID. */ private static final long serialVersionUID = 1L; /** The etablissement origine. */ @SecretaryExport @ManyToOne( fetch=FetchType.LAZY) @JoinColumn() private Etablissement etablissementOrigine; /** The date inscription. */ @SecretaryExport private Date dateInscription; /** The date soumission. */ @SecretaryExport private Date dateSoumission; /** The date modification. */ @SecretaryExport private Date secretariatChangeDate; /** The date de modification backup. */ @SecretaryExport private Date secretariatChangeDateBackup; /** The cas particulier. */ @SecretaryExport private Boolean casParticulier; /** The etat dossier. */ @SecretaryExport @ManyToOne( fetch=FetchType.LAZY) @JoinColumn() private EtatDossier etatDossier; /** The candidat. */ @SecretaryExport @OneToOne(fetch=FetchType.LAZY) private Candidat candidat; /** The info perso. */ @SecretaryExport @Obligatoire @ObligatoireSecretariat @OneToOne(cascade = { CascadeType.ALL },fetch=FetchType.LAZY,orphanRemoval = true) private InfoPerso infoPerso; /** The list formations. */ //@SecretaryExport @Obligatoire @ObligatoireSecretariat @OneToOne(cascade = { CascadeType.ALL },orphanRemoval = true) private ListFormations listFormations; /** The list cursus academique. */ @SecretaryExport @Obligatoire @ObligatoireSecretariat @OneToOne(cascade = { CascadeType.ALL },orphanRemoval = true) private ListCursusAcademique listCursusAcademique; /** The motivation centre interet. */ @SecretaryExport @Obligatoire @ObligatoireSecretariat @OneToOne(cascade = { CascadeType.ALL },orphanRemoval = true) private MotivationCentreInteret motivationCentreInteret; /** The entreprise. */ @SecretaryExport @Obligatoire @ObligatoireSecretariat @OneToOne(cascade = { CascadeType.ALL },orphanRemoval = true) private Entreprise entreprise; /** The list langues. */ @SecretaryExport @Obligatoire @ObligatoireSecretariat @OneToOne(cascade = { CascadeType.ALL },orphanRemoval = true) private ListLangues listLangues; /** The list sejour etranger. */ @SecretaryExport @Obligatoire @ObligatoireSecretariat @OneToOne(cascade = { CascadeType.ALL },orphanRemoval = true) private ListSejourEtranger listSejourEtranger; /** The list exp entreprise. */ @SecretaryExport @Obligatoire @ObligatoireSecretariat @OneToOne(cascade = { CascadeType.ALL },orphanRemoval = true) private ListExpEntreprise listExpEntreprise; /** The list referents. */ @SecretaryExport @Obligatoire @ObligatoireSecretariat @OneToOne(cascade = { CascadeType.ALL},orphanRemoval = true) private ListReferents listReferents; /** The info paiement. */ @SecretaryExport @Obligatoire @ObligatoireSecretariat @OneToOne(cascade = { CascadeType.ALL},orphanRemoval = true) private InfoPaiement infoPaiement; /** The avis jury. */ @OneToMany(mappedBy= "dossier",cascade = { CascadeType.ALL},orphanRemoval = true) private Set<AvisJury> avisJury = new HashSet<>(); /** The list documents supplementaires. */ @Obligatoire @ObligatoireSecretariat @OneToOne(cascade = { CascadeType.ALL },orphanRemoval = true) private ListDocumentsSupplementaires listDocumentsSupplementaires; /** The list fichier. */ @OneToMany(mappedBy = "dossier",cascade = { CascadeType.ALL },orphanRemoval = true) private Set<Fichier> listFichier; /** The list avis examinateur. */ @OneToMany(mappedBy= "dossier",orphanRemoval = true) private Set<AvisExaminateur> listAvisExaminateur; /** The list commentaire. */ @OneToMany(cascade = { CascadeType.ALL},orphanRemoval = true) private Set<Commentaire> listCommentaire; /** The validation commentaire. */ @Column(length = 500) @Pattern(regexp="^(.|n|r|t)*$")//accepte tous les caractères et les retours lignes private String validationCommentaire; } 这有什么问题? 解决方法
正如我在我的书High-Performance Java Persistence中所解释的那样,除非你打算修改它们,否则你永远不应该获取实体.因此,如果您只需要一个只读视图,那么您应该使用DTO projection instead. 假设您确实需要获取整个图形,因为您计划对其进行修改,那么您必须使用以下提取策略: 您可以在第一个查询中获取尽可能多的子@OneToOne和@ManyToOne实体关联,也可以在ATOTT @OneToMany或@ManyToMany中获取. 对于剩余的@OneToMany或@ManyToMany,您必须使用辅助查询.但是,您不希望在N+1 fashion中执行此操作,因此您需要在传递使用第一个查询获取的根实体时运行JPQL查询. 请记住,如果将二级集合重新组合到根实体上,则会在根实体上触发一些不需要的修改.因此,如果要将根实体传递给Web层,则应以只读模式获取它们. 同样,如果您不需要实体,那么您应该只获取DTO投影并使用ResultTransfomer将表格式投影转换为DTO图形,如this article中所述.
从这些映射中,不清楚为什么要执行该查询,但是您可以在datasource-proxy level在Hibernate中轻松调试它,并查看堆栈跟踪以查看触发它的内容. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |