【问题标题】:Using JpaSpecificationExecutor with EntityGraph将 JpaSpecificationExecutor 与 EntityGraph 一起使用
【发布时间】:2021-11-30 14:01:15
【问题描述】:

我正在使用 JpaSpecificationExecutor 的实现,并尝试在存储库中使用 @EntityGraph 来选择他们在复杂查询中获得的关系实体。

我的实体示例(所有关系双向)

@Entity
@Table(name = "trazabilidad_contenedor")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class TrazabilidadContenedor implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "traConSeq")
    @SequenceGenerator(name = "traConSeq")
    private Long id;

    @ManyToOne(optional = false)
    @NotNull
    @JsonIgnoreProperties(value = "trazabilidadContenedors", allowSetters = true)
    private PromoProGesCodLer promoProGesCodeLer;
       .
       .
       .

@Entity
@Table( name = "promo_pro_ges_cod_ler")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class PromoProGesCodLer implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    private Long id;
   
    @ManyToOne(optional = false)
    @NotNull
    @JsonIgnoreProperties(value = "promoProGesCodLers", allowSetters = true)
    private ProGesCodLer procesoGestoraCodLer;

    @ManyToOne(optional = false)
    @NotNull
    @JsonIgnoreProperties(value = "promoProGesCodLers", allowSetters = true)
    private Promocion promocion;
       .
       .
       .

@Entity
@Table(name = "promocion")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Promocion implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    private Long id;
       .
       .
       .
@Entity
@Table(name = "pro_ges_cod_ler")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@NextProGesCodLer
public class ProGesCodLer implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "pgclSeq")
    @SequenceGenerator(name = "pgclSeq")
    private Long id;

    @OneToMany(mappedBy = "procesoGestoraCodLer")
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    private Set<PromoProGesCodLer> promoProGesCodLers = new HashSet<>();

    @ManyToOne(optional = false)
    @NotNull
    @JsonIgnoreProperties(value = "proGesCodLers", allowSetters = true)
    private ProcesoGestora procesoGestora;
       .
       .
       .

这是我的仓库

@Repository
public interface TrazabilidadContenedorRepository
    extends JpaRepository<TrazabilidadContenedor, Long>, JpaSpecificationExecutor<TrazabilidadContenedor> {
@EntityGraph (
            type = EntityGraph.EntityGraphType.FETCH,
            attributePaths = {
                    "promoProGesCodeLer",
                    "promoProGesCodeLer.promocion",
                    "promoProGesCodeLer.promocion.direccion",
                    "promoProGesCodeLer.promocion.direccion.municipio",
                    "promoProGesCodeLer.procesoGestoraCodLer.procesoGestora",
                    "promoProGesCodeLer.procesoGestoraCodLer.codLER",
                    "promoProGesCodeLer.procesoGestoraCodLer.codLER.lerType",
                    "promoProGesCodeLer.procesoGestoraCodLer.nextProGesCodLer",
                    "promoProGesCodeLer.procesoGestoraCodLer.procesoGestora",
                    "promoProGesCodeLer.procesoGestoraCodLer.procesoGestora.gestora",
                  
            }
    )
    List<TrazabilidadContenedor> findAll(Specification<TrazabilidadContenedor> var1);
}

我的 Specification‹TrazabilidadContenedor›的构造函数

protected Specification<TrazabilidadContenedor> createSpecification(TrazabilidadContenedorCriteria criteria) {
        Specification<TrazabilidadContenedor> specification = Specification.where(null);
        if (criteria != null) {
            if (criteria.getPromocionId() != null) {
                specification =
                    specification.and((root, query, builder) ->
                                    builder.equal(
                                            root
                                                .join(TrazabilidadContenedor_.promoProGesCodeLer, JoinType.LEFT)
                                                .join(PromoProGesCodLer_.promocion, JoinType.LEFT)
                                                .get(Promocion_.id),
                                            criteria.getPromocionId()
                                    )
                    );
            }
            if (criteria.getGestoraId() != null) {
                specification =
                    specification.and(
                        (root, query, builder) ->
                                    builder.equal(
                                            root
                                                    .join(TrazabilidadContenedor_.promoProGesCodeLer, JoinType.LEFT)
                                                    .join(PromoProGesCodLer_.procesoGestoraCodLer, JoinType.LEFT)
                                                    .join(ProGesCodLer_.procesoGestora, JoinType.LEFT)
                                                    .join(ProcesoGestora_.gestora, JoinType.LEFT)
                                                    .get(Gestora_.id),
                                            criteria.getGestoraId()
                                    )
                    );
            }
        }
        return specification;
    }

当我只有一个条件时,criteria.getPromocionId() 或 criteria.getGestoraId() 没关系,但如果我同时使用这两个条件,我会获得。

Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=generatedAlias2,role=com.cocircular.greenadvisor.domain.PromoProGesCodLer.promocion,tableName=promocion,tableAlias=promocion2_,origin=promo_pro_ges_cod_ler promoproge1_,columns={promoproge1_.promocion_id,className=com.cocircular.greenadvisor.domain.Promocion}}] [select generatedAlias0 from com.cocircular.greenadvisor.domain.TrazabilidadContenedor as generatedAlias0 inner join generatedAlias0.promoProGesCodeLer as generatedAlias1 inner join generatedAlias1.promocion as generatedAlias2 inner join generatedAlias0.promoProGesCodeLer as generatedAlias3 inner join generatedAlias3.procesoGestoraCodLer as generatedAlias4 inner join generatedAlias4.procesoGestora as generatedAlias5 inner join generatedAlias5.gestora as generatedAlias6 where ( generatedAlias0.traceabilityStatus=:param0 ) and ( ( generatedAlias6.id=75304L ) and ( generatedAlias2.id=86754L ) )]
  at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:138)
  at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1542)
  at org.hibernate.query.Query.getResultList(Query.java:165)
  at org.hibernate.query.criteria.internal.compile.CriteriaQueryTypeQueryAdapter.getResultList(CriteriaQueryTypeQueryAdapter.java:76)

为此,我使用 Hibernate 5.4.15 和 Spring-Boot 2.2.7.RELEASE。

【问题讨论】:

    标签: spring hibernate spring-data-jpa jhipster


    【解决方案1】:

    生成的 sql 中呈现的每一项都必然会出现在图中。 所以,让我们写一个完整的图路径:

    select generatedAlias0 
    from com.cocircular.greenadvisor.domain.TrazabilidadContenedor as generatedAlias0 
        inner join generatedAlias0.promoProGesCodeLer as generatedAlias1 ---> promoProGesCodeLer
        inner join generatedAlias1.promocion as generatedAlias2          ---> promoProGesCodeLer.promocion
        inner join generatedAlias0.promoProGesCodeLer as generatedAlias3 ---> promoProGesCodeLer
        inner join generatedAlias3.procesoGestoraCodLer as generatedAlias4 ---> promoProGesCodeLer.procesoGestoraCodLer
        inner join generatedAlias4.procesoGestora as generatedAlias5        ---> promoProGesCodeLer.procesoGestoraCodLer.procesoGestora
        inner join generatedAlias5.gestora as generatedAlias6               ----> promoProGesCodeLer.procesoGestoraCodLer.procesoGestora.gestora
        
    where ( generatedAlias0.traceabilityStatus=:param0 ) 
        and ( ( generatedAlias6.id=75304L ) and ( generatedAlias2.id=86754L ) )
    

    这是提供的图表:

    attributePaths = {
        "promoProGesCodeLer",
        "promoProGesCodeLer.promocion",
        "promoProGesCodeLer.promocion.direccion",
        "promoProGesCodeLer.promocion.direccion.municipio",
        "promoProGesCodeLer.procesoGestoraCodLer.procesoGestora",
        "promoProGesCodeLer.procesoGestoraCodLer.codLER",
        "promoProGesCodeLer.procesoGestoraCodLer.codLER.lerType",
        "promoProGesCodeLer.procesoGestoraCodLer.nextProGesCodLer",
        "promoProGesCodeLer.procesoGestoraCodLer.procesoGestora",
        "promoProGesCodeLer.procesoGestoraCodLer.procesoGestora.gestora" }
    

    在我看来,图中缺少节点 promoProGesCodeLer.procesoGestoraCodLer

    【讨论】:

    • 不,对不起,是一样的。问题是当我的 Specification‹T› 有 2 个条件时,只有一个条件可以。
    • @AleXxSnJR,您是否可以为您的代码制作一个可运行的示例并将其放在 github 上? P.s 我想,没有 entityGraph 可以正常工作吗?
    猜你喜欢
    • 2014-12-05
    • 1970-01-01
    • 1970-01-01
    • 2020-05-23
    • 2018-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多