代码之家  ›  专栏  ›  技术社区  ›  Pilpin

使用@IndexingDependence派生自和属性桥

  •  0
  • Pilpin  · 技术社区  · 4 年前

    我想使用hibernate搜索 @IndexingDependency 用一个 PropertyBridge 但我似乎无法让它工作。

    我得到了这个错误:

    Hibernate ORM mapping: type 'com.something.Person': path '.currentStatus': 
      failures: 
        - HSEARCH700020: Unable to find the inverse side of the association on type
        'com.something.Person' at path '.currentStatus<no value extractors>'. Hibernate Search
        needs this information in order to reindex 'com.something.Person' when
        'com.something.Status' is modified. You can solve this error by defining the inverse
        side of this association,  either with annotations specific to your integration
        (@OneToMany(mappedBy = ...) in Hibernate ORM)  or with the  Hibernate Search 
        @AssociationInverseSide annotation. Alternatively, if you do not need to reindex 
        'com.something.Person' when 'com.something.Status' is modified, you can disable 
         automatic reindexing with @IndexingDependency(reindexOnUpdate = ReindexOnUpdate.SHALLOW)
    

    不确定我是否做错了什么,或者我试图做的事情是否不可能。谢谢你的帮助。

    以下是相关文件。

    人班

    @Entity
    @Table
    @Indexed
    public class Person {
        @OneToMany(mappedBy = "patient", cascade = CascadeType.ALL) 
        private Set<Status> status = new HashSet<>();
    
        @Transient
        @StatusBinding(fieldName = "currentStatus")
        @IndexingDependency(derivedFrom = @ObjectPath(@PropertyValue(propertyName = "status")))
        public Status getCurrentStatus() {
            return this.status.stream()
                .filter(it -> it.getDate().isAfter(LocalDate.now()))
                .max(Comparator.comparing(Status::getDate))
                .orElse(null);
        }
    }
    

    状态绑定。班

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.FIELD})
    @PropertyMapping(processor = @PropertyMappingAnnotationProcessorRef(type = StatusBinding.Processor.class))
    @Documented
    public @interface StatusBinding {
    
        String fieldName() default "";
    
        class Processor implements PropertyMappingAnnotationProcessor<StatusBinding> {
            @Override
            public void process(PropertyMappingStep mapping, StatusBindingannotation, PropertyMappingAnnotationProcessorContext context) {
                StatusBinderbinder = new StatusBinder();
                if (!annotation.fieldName().isBlank()) binder.setFieldName(annotation.fieldName());
                mapping.binder(binder);
            }
        }
    }
    

    活页夹。班

    public class StatusBinder implements PropertyBinder {
        @Setter private String fieldName = "mainStatus";
    
        @Override
        public void bind(PropertyBindingContext context) {
            context.dependencies()
                .use("status")
                .use("date")
                .use("note");
    
            IndexSchemaObjectField mainStatusField = context.indexSchemaElement().objectField(this.fieldName);
    
            context.bridge(Status.class, new StatusBridge(
                    mainStatusField.toReference(),
                    mainStatusField.field("status", context.typeFactory().asString()).toReference(),
                    mainStatusField.field("date", context.typeFactory().asLocalDate()).toReference(),
                    mainStatusField.field("note", context.typeFactory().asString()).toReference()
            ));
        }
    
        private static class StatusBrige implements PropertyBridge<Status> {
            private final IndexObjectFieldReference mainStatusField;
            private final IndexFieldReference<String> statusField;
            private final IndexFieldReference<LocalDate> dateField;
            private final IndexFieldReference<String> noteField;
    
            public StatusBrige(
                    IndexObjectFieldReference mainStatusField,
                    IndexFieldReference<String> statusField,
                    IndexFieldReference<LocalDate> dateField,
                    IndexFieldReference<String> noteField
            ) {
                this.mainStatusField = mainStatusField;
                this.statusField = statusField;
                this.dateField = dateField;
                this.noteField = noteField;
            }
    
            @Override
            public void write(DocumentElement target, Status mainStatus, PropertyBridgeWriteContext context) {
                DocumentElement statutElement = target.addObject(this.mainStatusField);
                statutElement.addValue(this.statusField, mainStatus.getStatus);
                statutElement.addValue(this.dateField, mainStatus.getDate());
                statutElement.addValue(this.noteField, mainStatus.getNote());
            }
        }
    }
    
    0 回复  |  直到 4 年前
        1
  •  1
  •   yrodiere    4 年前

    问题

    Status 实体被修改,Hibernate搜索不知道如何检索相应的 Person 有那个 地位 作为它的 currentStatus .

    解决方案

    假设 当前状态 总是包含在 status ,之后呢 Status.patient 是地球的反面 Person.status 关联,您只需添加以下内容:

        @Transient
        @StatusBinding(fieldName = "currentStatus")
        @IndexingDependency(derivedFrom = @ObjectPath(@PropertyValue(propertyName = "status")))
        // ADD THIS ANNOTATION
        @AssociationInverseSide(
                inversePath = @ObjectPath(@PropertyValue(propertyName = "patient"))
        )
        public Status getCurrentStatus() {
           // ...
        }
    

    为什么?

    我会尽力解释的,但有点复杂,请耐心听我说。

    派生属性和关联的反面是相关概念:它们的共同目的是允许Hibernate搜索执行自动重新索引。

    然而,它们仍然是独立的概念,Hibernate搜索无法从中推断出其中一个。

    具有 @IndexingDependency(derivedFrom) ,您定义的是 当前状态 取决于:

        @IndexingDependency(derivedFrom = @ObjectPath(@PropertyValue(propertyName = "status")))
        public Status getCurrentStatus() {
    

    这告诉Hibernate Search 当前状态 无论何时 地位 财产变动。有了这些信息,Hibernate Search就可以在您调用 person.getStatus().remove(...) person.getStatus().add(...) (例如)你的 实体需要重新编制索引,因为 当前状态 被编入索引,它可能会改变。

    在定制活页夹中,您还可以 defining dependencies :

            context.dependencies()
                .use("status")
                .use("date")
                .use("note");
    

    这告诉Hibernate Search 地位 , date note a的性质 地位 实体变化 有那个 地位 作为它的 当前状态 需要重新编制索引。

    然而Hibernate搜索不知道如何检索拥有该功能的人 地位 作为它的 当前状态 .

    它可能知道如何取回所有拥有它的人 地位 在他们的 地位 布景,但那是另一回事,不是吗?Hibernate Search不知道这一点 当前状态 实际上是 地位 所有物据它所知, getCurrentStatus() 很可能是这样的: status.iterator().next().getParentStatus() .那么当前状态将不包括在 Person#status ,目前尚不清楚 myStatus.getPatient() 可以退回一个 谁的 当前状态 myStatus .

    所以你需要明确地告诉Hibernate Search:“从给定的 Status myStatus ,如果检索 迈斯塔特斯。getPatient() ,你得到 谁的 当前状态 财产可以追溯到 迈斯塔特斯 “.这就是 @AssociationInverseSide 是给你的。

    推荐文章