当对象通过@NorePositoryBean JPA方法删除对象时,Hibernate搜索不会从Lucene索引中删除旧值

发布于 2025-02-12 04:17:58 字数 5508 浏览 0 评论 0原文

我有一个norePositoryBean JPA接口,该接口具有一种称为deleteallbyidin(...)的自定义JPA方法,该方法由某些混凝土JParepoSitories继承。由于某种原因,此自定义删除方法被Hibernate Search忽略了。每当通过此自定义方法删除实体时,在删除完成后,都不会从Lucene索引中删除其值。我将在这篇文章下进一步解释问题;但是首先,这是代码

@NoRepositoryBean
public interface NameTranslationDao<T extends NameTranslation> extends JpaRepository<T, Long> {

    @Modifying
    @Transactional
    @Query(value = "DELETE FROM #{#entityName} c WHERE c.id IN :translationsToDelete")
    public void deleteAllByIdIn(@Param("translationsToDelete") Set<Long> translationsToDelete);

}

JPAREPOSITOR子类,该子类扩展以下接口:

@Repository
@Transactional(readOnly = true)
public interface LifeStageCommonNameTranslationDao extends CommonNameTranslationDao<LifeStageCommonNameTranslation> {

}

在混凝土JParepository和NametranslationDao NorePositoryBean之间,还有另一个@NorePositoryBean接口。该人称为commonNemetrantlationdao,但它并没有以任何方式覆盖自定义方法,因此,这不太可能是问题的原因,尽管如此,它仍然是该存储库的代码:

@NoRepositoryBean
public interface CommonNameTranslationDao<T extends NameTranslation> extends NameTranslationDao<T> {

    @Deprecated
    @Transactional(readOnly = true)
    @Query("SELECT new DTOs.AutoCompleteSuggestion(u.parent.id, u.autoCompleteSuggestion) FROM #{#entityName} u WHERE u.autoCompleteSuggestion LIKE :searchString% AND deleted = false  AND (u.language.id = :preferredLanguage OR u.language.id = :defaultLanguage)")
    List<AutoCompleteSuggestion> findAllBySearchStringAndDeletedIsFalse(@Param("searchString") String searchString, @Param("preferredLanguage") Long preferredLanguage, @Param("defaultLanguage") Long defaultLanguage);

    @Transactional(readOnly = true)
    @Query(nativeQuery = true, value = "SELECT s.translatedName FROM #{#entityName} s WHERE s.language_id = :preferredLanguage AND s.parent_id = :parentId LIMIT 1")
    public String findTranslatedNameByParentAndLanguage(@Param("preferredLanguage") Long languageId, @Param("parentId") Long parentId);

    @Modifying
    @Transactional
    @Query(nativeQuery = true, value = "DELETE FROM #{#entityName} WHERE id = :id")
    void hardDeleteById(@Param("id") Long id);

    @Modifying
    @Transactional
    @Query(nativeQuery = true, value = "UPDATE #{#entityName} c SET c.deleted = TRUE WHERE c.id = :id")
    void softDeleteById(@Param("id") Long id);

}

此外,此外,此外,还将lifestagecommonnemetrantlation entity类:

    @Entity
    @Indexed
    @Table(
            uniqueConstraints = {
                    @UniqueConstraint(name = "UC_life_cycle_type_language_id_translatedName", columnNames = {"translatedName", "parent_id", "language_id"})
            },
            indexes = {
                    @Index(name = "IDX_lifestage", columnList = "parent_id"),
                    @Index(name = "IDX_translator", columnList = "user_id"),
                    @Index(name = "IDX_species_language", columnList = "language_id, parent_id, deleted"),
                    @Index(name = "IDX_autoCompleteSuggestion_language", columnList = "autoCompleteSuggestion, language_id, deleted")})
    public class LifeStageCommonNameTranslation extends NameTranslation<LifeStage> implements AuthorizationSubject {
    
        @Id @DocumentId
        @GenericGenerator(
                name = "sequenceGeneratorLifeStageCommonNameTranslation",
                strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
                parameters = {
                        @org.hibernate.annotations.Parameter(name = "sequence_name", value = "_lifestagecommonnametranslation_hibernate_sequence"),
                        @org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled"),
                        @org.hibernate.annotations.Parameter(name = "initial_value", value = "1"),
                        @org.hibernate.annotations.Parameter(name = "increment_size", value = "25"),
                        @org.hibernate.annotations.Parameter(name = "prefer_sequence_per_entity", value = "true")
                }
        )
        @GeneratedValue(
                strategy = GenerationType.SEQUENCE,
                generator = "sequenceGeneratorLifeStageCommonNameTranslation"
        )
        @Field(analyze = Analyze.NO, store = Store.YES, name = "parentId")
        private Long id;
    
        @IndexedEmbedded(includeEmbeddedObjectId = true)
        @ManyToOne(fetch = FetchType.LAZY)
        private LifeStage parent;
    
        @Field(index = NO, store = Store.YES)
        private String autoCompleteSuggestion;

//Getters and setters ommitted

问题是:每当我使用lifestagecommonnemetranslationdao上的继承deleteallbyidin()方法时,代码>将不会从lucene index删除实体后,不会从autoCompleteSuggestion字段值中删除。但是,如果我使用标准deleteByid() jParepository方法删除实体,则字段值 是从lucene index中删除的。

自定义和标准删除方法均在@transactional注释方法中调用,我还将随后立即称为flush() jparepository方法。我这样做是因为我已经读到这有时可以帮助更新Lucene索引。但是,在deleteallbyidin()呼叫flush()之后根本没有帮助。

我已经排除了问题的可能性,即问题是由SQL查询中的Spel表达式引起的。我通过用> lifestageCommonTranslation替换#{#entityName}来对此进行测试。但是问题仍然存在。 Lucene索引仍未删除删除后autoSuggestionText字段值。

我可以通过简单地使用标准JPA方法deletebyid()来轻松解决此问题更新Lucene索引。

I have a NoRepositoryBean Jpa interface that has one custom jpa method called deleteAllByIdIn(...) which is inherited by some concrete JpaRepositories. For some reason this custom delete method is ignored by Hibernate Search. Whenever an entity is deleted through this custom method its value is not removed from the lucene index after the delete is done. I will explain the problem some more further down this post; but first here's the code

@NoRepositoryBean
public interface NameTranslationDao<T extends NameTranslation> extends JpaRepository<T, Long> {

    @Modifying
    @Transactional
    @Query(value = "DELETE FROM #{#entityName} c WHERE c.id IN :translationsToDelete")
    public void deleteAllByIdIn(@Param("translationsToDelete") Set<Long> translationsToDelete);

}

Heres a JpaRepository subclass that extends this interface:

@Repository
@Transactional(readOnly = true)
public interface LifeStageCommonNameTranslationDao extends CommonNameTranslationDao<LifeStageCommonNameTranslation> {

}

Theres another @NoRepositoryBean interface in-between the concrete JpaRepository and the NameTranslationDao NoRepositoryBean. That one is called CommonNameTranslationDao but it doesn't override the custom method in any way, so it is unlikely the cause of the problem, nevertheless heres the code of that repository:

@NoRepositoryBean
public interface CommonNameTranslationDao<T extends NameTranslation> extends NameTranslationDao<T> {

    @Deprecated
    @Transactional(readOnly = true)
    @Query("SELECT new DTOs.AutoCompleteSuggestion(u.parent.id, u.autoCompleteSuggestion) FROM #{#entityName} u WHERE u.autoCompleteSuggestion LIKE :searchString% AND deleted = false  AND (u.language.id = :preferredLanguage OR u.language.id = :defaultLanguage)")
    List<AutoCompleteSuggestion> findAllBySearchStringAndDeletedIsFalse(@Param("searchString") String searchString, @Param("preferredLanguage") Long preferredLanguage, @Param("defaultLanguage") Long defaultLanguage);

    @Transactional(readOnly = true)
    @Query(nativeQuery = true, value = "SELECT s.translatedName FROM #{#entityName} s WHERE s.language_id = :preferredLanguage AND s.parent_id = :parentId LIMIT 1")
    public String findTranslatedNameByParentAndLanguage(@Param("preferredLanguage") Long languageId, @Param("parentId") Long parentId);

    @Modifying
    @Transactional
    @Query(nativeQuery = true, value = "DELETE FROM #{#entityName} WHERE id = :id")
    void hardDeleteById(@Param("id") Long id);

    @Modifying
    @Transactional
    @Query(nativeQuery = true, value = "UPDATE #{#entityName} c SET c.deleted = TRUE WHERE c.id = :id")
    void softDeleteById(@Param("id") Long id);

}

Also, heres the code of the LifeStageCommonNameTranslation entity class:

    @Entity
    @Indexed
    @Table(
            uniqueConstraints = {
                    @UniqueConstraint(name = "UC_life_cycle_type_language_id_translatedName", columnNames = {"translatedName", "parent_id", "language_id"})
            },
            indexes = {
                    @Index(name = "IDX_lifestage", columnList = "parent_id"),
                    @Index(name = "IDX_translator", columnList = "user_id"),
                    @Index(name = "IDX_species_language", columnList = "language_id, parent_id, deleted"),
                    @Index(name = "IDX_autoCompleteSuggestion_language", columnList = "autoCompleteSuggestion, language_id, deleted")})
    public class LifeStageCommonNameTranslation extends NameTranslation<LifeStage> implements AuthorizationSubject {
    
        @Id @DocumentId
        @GenericGenerator(
                name = "sequenceGeneratorLifeStageCommonNameTranslation",
                strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
                parameters = {
                        @org.hibernate.annotations.Parameter(name = "sequence_name", value = "_lifestagecommonnametranslation_hibernate_sequence"),
                        @org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled"),
                        @org.hibernate.annotations.Parameter(name = "initial_value", value = "1"),
                        @org.hibernate.annotations.Parameter(name = "increment_size", value = "25"),
                        @org.hibernate.annotations.Parameter(name = "prefer_sequence_per_entity", value = "true")
                }
        )
        @GeneratedValue(
                strategy = GenerationType.SEQUENCE,
                generator = "sequenceGeneratorLifeStageCommonNameTranslation"
        )
        @Field(analyze = Analyze.NO, store = Store.YES, name = "parentId")
        private Long id;
    
        @IndexedEmbedded(includeEmbeddedObjectId = true)
        @ManyToOne(fetch = FetchType.LAZY)
        private LifeStage parent;
    
        @Field(index = NO, store = Store.YES)
        private String autoCompleteSuggestion;

//Getters and setters ommitted

The problem is the following: Whenever i use the inherited deleteAllByIdIn() method on LifeStageCommonNameTranslationDao then Hibernate Search will not remove the autoCompleteSuggestion field value from the lucene index after the entity has been deleted. If however i use the standard deleteById() JpaRepository method to delete the entity then the field value is removed from the lucene index.

Both the custom and the standard delete method were called within a @Transactional annotated method and i also called the flush() jpaRepository method right afterwards. I did this because I've read that this can sometimes help to update the lucene index. But in the case of deleteAllByIdIn() calling flush() afterwards did not help at all.

I already ruled out the possiblity that the problem was caused by the spEL expression in the SQL query. I tested this by replacing #{#entityName} with a concrete entity name like LifeStageCommonTranslation and then calling the deleteAllByIdIn() delete method. But the problem still persisted. The lucene index still did not remove the autoSuggestionText field value after the delete.

I can easily solve this problem by simply using the standard jpa method deleteById() but i want to know why the custom made jpa method deleteAllByIdIn() does not cause Hibernate search to update the lucene index.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

云柯 2025-02-19 04:17:58

Hibernate搜索检测Hibernate Orm Session/EntityManager中发生的实体更改事件。这不包括insert/更新/delete您在jpql或本机SQL查询中写的语句。

限制在此处记录: https://docs.jboss.org/hibernate/stable/search/reference/en-us/html_single/#limitations-limitations-changes-in-session

也记录下来的解决方法:

一个解决方法是在运行jpql/sql查询后明确依次扣押,要么使用 massIndexer 手动

编辑:当然,您的解决方法也可能有效,如果deletebyid在删除它之前会加载实体(我不太熟悉Spring Data JPA的内部内容):

我可以通过简单地使用标准JPA方法DeleteById()轻松解决此问题,但是我想知道为什么定制的JPA方法DeletealBbyIdin()不会导致Hibernate搜索以更新Lucene索引。

Hibernate Search detects entity change events happening in your Hibernate ORM Session/EntityManager. This excludes insert/update/delete statements that you wrote yourself in JPQL or native SQL queries.

The limitation is documented here: https://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#limitations-changes-in-session

The workaround is documented there too:

One workaround is to reindex explicitly after you run JPQL/SQL queries, either using the MassIndexer or manually.

EDIT: And of course your workaround might be valid as well, if deleteById loads the entity in the session before deleting it (I'm not that familiar with the internals of Spring Data JPA):

I can easily solve this problem by simply using the standard jpa method deleteById() but i want to know why the custom made jpa method deleteAllByIdIn() does not cause Hibernate search to update the lucene index.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文