hibernate-search - 使用 @IndexingDependency derivedFrom 和属性桥
问题描述
我想将休眠搜索@IndexingDependency
与 a一起使用,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);
}
}
状态绑定.class
@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);
}
}
}
StatusBinder.class
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());
}
}
}
解决方案
问题
当一个Status
实体被修改时,Hibernate Search 不知道如何检索相应Person
的将其Status
作为其currentStatus
.
解决方案
假设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 Search 执行自动重新索引的共同目的。
但是,它们仍然是独立的概念,Hibernate Search 无法从中推断出一个。
使用@IndexingDependency(derivedFrom)
,您正在定义的计算currentStatus
取决于:
@IndexingDependency(derivedFrom = @ObjectPath(@PropertyValue(propertyName = "status")))
public Status getCurrentStatus() {
这告诉 Hibernate SearchcurrentStatus
将在status
属性更改时更改。有了这些信息,Hibernate Search 就能够确定无论何时您调用person.getStatus().remove(...)
或person.getStatus().add(...)
(例如)您的Person
实体需要重新索引,因为currentStatus
已编入索引,并且它可能已更改。
在您的自定义活页夹中,您还定义了依赖项:
context.dependencies()
.use("status")
.use("date")
.use("note");
这告诉 Hibernate Search,每当实体的 、 和 属性发生变化时status
,date
都note
需要重新索引。Status
Person
Status
currentStatus
但是...... Hibernate Search 不知道的是如何检索将其Status
作为currentStatus
.
它可能知道如何检索所有Status
在他们的status
集合中拥有它的人,但这是另一回事,不是吗?Hibernate Search 不知道这currentStatus
实际上是status
属性中包含的元素之一。据它所知,getCurrentStatus()
很可能会这样做:status.iterator().next().getParentStatus()
. 那么当前状态不会包含在 中Person#status
,并且不清楚是否myStatus.getPatient()
可以返回Person
who currentStatus
is myStatus
。
因此,您需要明确告诉 Hibernate Search:“从给定的Status myStatus
中,如果您检索 的值myStatus.getPatient()
,您将获得Person
其currentStatus
属性可能指向的myStatus
”。这正是@AssociationInverseSide
它的用途。
推荐阅读
- bluetooth-lowenergy - iBeacon 名称未显示在 ESP32 BLE 扫描仪中
- swift - 将 ARFaceGeometry 保存到 OBJ 文件
- vue.js - 找不到Vue js路由404和资产
- laravel - Laravel 说在表单中给出动作时缺少必需的参数
- r - 如何以一定次数重复堆叠同一行
- google-apps-script - 如何在谷歌电子表格中 B 列的每个填充单元格中获取文本
- nginx - Apache Zeppelin websockets 是否经过身份验证?
- python - Tensorflow 的 name_scope 在 Tensorboard 中不起作用
- python-3.x - AttributeError:模块'pygame.event'没有属性'type'
- python - 如何在函数内打印变量