Spring data JPA – using @EntityGraph causes "Entity graph specified is not applicable to the entity" warning

huangapple go评论71阅读模式
英文:

Spring data JPA - using @EntityGraph causes "Entity graph specified is not applicable to the entity" warning

问题

我将应用程序从Spring Boot 2.2.5升级到了2.3.3,并且在应用中使用了Spring Data JPA Starter 5.4.20.Final。我的实体在编译时进行了增强。

现在,当我在从JpaRepository重写的findAll方法上使用带有attributePaths属性的@EntityGraph注解时,我收到以下警告:

2020-08-19 12:13:41.121  WARN 9348 --- [nio-8060-exec-3] [] [] o.h.engine.internal.TwoPhaseLoad         : 指定的实体图不适用于实体 [DictionaryLang(id=1601, name=null, lang=null)]。已忽略。
2020-08-19 12:13:41.483  WARN 9348 --- [nio-8060-exec-3] [] [] o.h.engine.internal.TwoPhaseLoad         : 指定的实体图不适用于实体 [DictionaryValueLang(id=3051, lang=null, name=null)]。已忽略。

尽管有这个警告,实际上图形是被正确获取的 - 我可以在日志中看到只有一个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 );
}
英文:

I upgraded my app from spring boot 2.2.5 to 2.3.3 and I'm using spring data JPA starter with 5.4.20.Final onboard. My entites are enhanced at compile time.

Now when I'm using @EntityGraph annotation with attributePaths property over overriden findAll method from JpaRepository I'm getting this warning:

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.

Even though this warning - graph is fetched properly - I can see only one SQL query in the logs and the app behaves as before an update.

Here's my repository code:

public interface DictionaryRepository extends JpaRepository&lt;Dictionary, Long&gt;, QuerydslPredicateExecutor&lt;Dictionary&gt; {

    @EntityGraph(attributePaths = {&quot;langs&quot;, &quot;values&quot;, &quot;values.langs&quot;})
    @Override
    Page&lt;Dictionary&gt; findAll(Predicate predicate, Pageable pageable);
}

And here're my entities:

@Entity
@Table(name = &quot;DICTIONARIES&quot;)
public class Dictionary {

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

    @OrderBy(&quot;ordinal ASC&quot;)
    @OneToMany(mappedBy = &quot;dictionary&quot;, fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List&lt;DictionaryValue&gt; values;

    @OneToMany(mappedBy = &quot;dictionary&quot;, fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private Set&lt;DictionaryLang&gt; langs;

}


@Entity
@Table(name = &quot;DICTIONARY_LANGS&quot;)
public class DictionaryLang extends BaseEntity {

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

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

}

How to solve this warning? I can see that this warning is happening inside those lines of hibernate's TwoPhaseLoad class:

GraphImplementor fetchGraphContext = session.getFetchGraphLoadContext();
if ( fetchGraphContext != null &amp;&amp; !fetchGraphContext.appliesTo( entity.getClass() ) ) {
	LOG.warnf( &quot;Entity graph specified is not applicable to the entity [%s]. Ignored.&quot;, entity);
	fetchGraphContext = null;
	session.setFetchGraphLoadContext( null );
}

答案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") {
    // 移除新Spring中附带的Hibernate
    exclude group: "org.hibernate", module: "hibernate-core" 
}
// 添加旧版本的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

英文:

This is because of an update of hibernate to 5.4.20 in spring 2.3.3.

If you downgrade the hibernate tp 5.4.18 this problem will disappear, upgrade to 5.4.21 did not help.

In my case hibernate not just adding a warning message it actually ignores @EntityGraph(attributePaths = {...}) annotation and performs query generation according to mappings which in my case lead to a bench of N+1 problems and thousands of queries.
Also, EntityGraph.EntityGraphType.LOAD does not solve the problem, as in this case hibernate will load all mappings not mentioned in @EntityGraph according to mappings fetch type which may add a lot of queries if you fatch big collections.

See details About EntityGraphType

o downgrade hibernate you can use

 implementation (&quot;org.springframework.boot:spring-boot-starter-data-jpa&quot;) {
     // to remove fibernate that came with new spring
     exclude group: &quot;org.hibernate&quot;, module: &quot;hibernate-core&quot; 
 }
 // to add old hibernate 
 implementation &quot;org.hibernate:hibernate-core:5.4.18.Final&quot;

Here is a related issue in hibernate is https://hibernate.atlassian.net/browse/HHH-14124
it sais that the affected version 4.5.19 and fix version is 4.5.20.
but still, I am getting error in spring 2.3.3(hibernate 4.5.20)

UPDATE: here is the issue posted for this bug. it is already fixed:
https://hibernate.atlassian.net/browse/HHH-14212

huangapple
  • 本文由 发表于 2020年8月19日 18:38:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/63485177.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定