当对象通过@NorePositoryBean JPA方法删除对象时,Hibernate搜索不会从Lucene索引中删除旧值
我有一个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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
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
也记录下来的解决方法:
编辑:当然,您的解决方法也可能有效,如果
deletebyid
在删除它之前会加载实体(我不太熟悉Spring Data JPA的内部内容):Hibernate Search detects entity change events happening in your Hibernate ORM
Session
/EntityManager
. This excludesinsert
/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:
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):