Spring Data JPA - 使用 @EntityGraph 会导致 "Entity graph specified is not applicable to the entity" 警告。

9
我把我的应用从Spring Boot 2.2.5升级到2.3.3,使用了5.4.20.Final版本的Spring Data JPA starter。在编译时增强了我的实体。
现在,当我在覆盖JpaRepository的findAll方法时,在@EntityGraph注解中使用attributePaths属性时,会出现如下警告:
2020-08-19 12:13:41.121  WARN 9348 --- [nio-8060-exec-3] [] [] o.h.engine.internal.TwoPhaseLoad         : Entity graph specified is not applicable to the entity [DictionaryLang(id=1601, name=null, lang=null)]. Ignored.
2020-08-19 12:13:41.483  WARN 9348 --- [nio-8060-exec-3] [] [] o.h.engine.internal.TwoPhaseLoad         : Entity graph specified is not applicable to the entity [DictionaryValueLang(id=3051, lang=null, name=null)]. Ignored.

尽管这个警告——图表已经被正确地获取,但是我只能在日志中看到一个SQL查询,并且应用程序的行为与更新之前相同。
这是我的存储库代码:
public interface DictionaryRepository extends JpaRepository<Dictionary, Long>, QuerydslPredicateExecutor<Dictionary> {

    @EntityGraph(attributePaths = {"langs", "values", "values.langs"})
    @Override
    Page<Dictionary> findAll(Predicate predicate, Pageable pageable);
}

以下是我的实体:

@Entity
@Table(name = "DICTIONARIES")
public class Dictionary {

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

    @OrderBy("ordinal ASC")
    @OneToMany(mappedBy = "dictionary", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<DictionaryValue> values;

    @OneToMany(mappedBy = "dictionary", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<DictionaryLang> langs;

}


@Entity
@Table(name = "DICTIONARY_LANGS")
public class DictionaryLang extends BaseEntity {

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

    @ManyToOne(fetch = FetchType.LAZY)
    @LazyToOne(LazyToOneOption.PROXY)
    @JoinColumn(name = "DICTIONARY_ID")
    private Dictionary dictionary;

}

怎样解决这个警告?我可以看到这个警告是发生在 Hibernate 的 TwoPhaseLoad 类的这些行中:
GraphImplementor fetchGraphContext = session.getFetchGraphLoadContext();
if ( fetchGraphContext != null && !fetchGraphContext.appliesTo( entity.getClass() ) ) {
    LOG.warnf( "Entity graph specified is not applicable to the entity [%s]. Ignored.", entity);
    fetchGraphContext = null;
    session.setFetchGraphLoadContext( null );
}

1
你最近解决了这个问题吗?我现在也遇到了同样的问题,急需任何提示。 - Seb
2
我找到了一个适合我的解决方案:在存储库方法的EntityGraph注释中添加type = EntityGraph.EntityGraphType.LOAD。 - Seb
@Seb 谢谢 - 在我的情况下也有效。我想这是新的Spring Data中的一个错误。 - Michał Stochmal
1
我将spring-boot-starter-parent的版本从2.2.0.RELEASE升级到2.3.2.RELEASE,但没有更改任何代码,现在出现了这个问题。遵循@Seb的建议,在注释中定义EntityGraph.EntityGraphType.LOAD也解决了我的问题。 - kscherrer
我也遇到了这个问题。我不想改变我的实体图类型来加载,因为那不是我需要的,我不希望其他引用默认为它们的正常行为。 - Sebastiaan van den Broek
可以确认。我在升级到Spring Boot 2.3.4后看到了相同的日志警告,它引入了Hibernate 5.4.21。 - Zaki
1个回答

8
这是因为在Spring 2.3.3中升级了Hibernate到5.4.20版本。如果将Hibernate降级到5.4.18,此问题将消失,升级到5.4.21并不能解决该问题。在我的情况下,Hibernate不仅会添加警告消息,而且会忽略@EntityGraph(attributePaths = {...})注释,并根据映射执行查询生成,这在我的情况下导致了一堆N+1问题和成千上万的查询。此外,EntityGraph.EntityGraphType.LOAD也无法解决该问题,因为在这种情况下,Hibernate将根据映射获取类型加载未在@EntityGraph中提及的所有映射,如果获取大型集合,则可能会添加很多查询。有关详细信息,请参见EntityGraphType。要降级Hibernate,您可以使用:
 implementation ("org.springframework.boot:spring-boot-starter-data-jpa") {
     // to remove fibernate that came with new spring
     exclude group: "org.hibernate", module: "hibernate-core" 
 }
 // to add old hibernate 
 implementation "org.hibernate:hibernate-core:5.4.18.Final"

这里涉及到Hibernate的一个相关问题:https://hibernate.atlassian.net/browse/HHH-14124。该问题影响版本为4.5.19,修复版本为4.5.20。但是,我在使用Spring 2.3.3(Hibernate 4.5.20)时仍然遇到错误。 更新:针对此错误已发布了问题报告,并已经修复:https://hibernate.atlassian.net/browse/HHH-14212

3
实际上,我的所有关系都被指定为“懒加载”,因此使用EntityGraphType.LOAD并不是什么大问题,但谢谢你指出来。我宁愿降级整个Spring Data JPA - 我不能确定新版本的Spring Data是否会与旧版Hibernate发生冲突。 - Michał Stochmal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接