【问题标题】:Hibernate search: search in composite key EmbeddedIdHibernate 搜索:在复合键 EmbeddedId 中搜索
【发布时间】:2020-12-28 18:50:40
【问题描述】:

我将 CKey 类定义为嵌入式 id 类。

我定义了类BEntity,并为复合主键使用了双向字符串字段桥。

我将AEntityManyToOneBEntity 的关系定义为类。

@Entity @Indexed
public class AEntity {
    @ManyToOne(optional = false) @IndexedEmbedded(depth = 1, includeEmbeddedObjectId = true)
    @JoinColumns(value = { @JoinColumn(name = "fk_fId", referencedColumnName = "fId"),
            @JoinColumn(name = "fk_sId", referencedColumnName = "sId") }, foreignKey = @ForeignKey(name = "fk_sub"))
    private BEntity bEntity;
}

@Entity @Indexed
public class BEntity {
    @EmbeddedId @IndexedEmbedded @FieldBridge(impl = CompositeIdBridge.class)
    private CKey cKey;
}


@Embeddable @Indexed
public class CKey {
    @Field
    private String fId;
    @Field
    private String sId;
}

public class CompositeIdBridge implements TwoWayStringBridge {
    @Override
    public String objectToString(Object object) {
       return String.format("%s.%s", (CKey) object.getFId(), (CKey) object.getSId());
    }
    @Override
    public Object stringToObject(String stringValue) {
       String[] compositeIdProperties = stringValue.split("\\.");
       return new CKey(compositeIdProperties[1], compositeIdProperties[2]);
    }
}

然后,我尝试在实体类AEntity 上进行休眠搜索,但遇到了这个异常:

无法在 AEntity 中找到字段 bEntity.cKey.fId

Query query = getQuery().bool()
                .must(getQuery().keyword().onField("bEntity.cKey.fId").matching("111111").createQuery())
                .must(getQuery().keyword().onField("bEntity.cKey.sId").matching("222222").createQuery()).createQuery();
FullTextQuery fullTextQuery = getFullTextEntityManager().createFullTextQuery(query, AEntity.class);

【问题讨论】:

    标签: hibernate lucene hibernate-search


    【解决方案1】:

    AEntity 中的 @IndexedEmbedded(depth = 1) 明确要求仅嵌入深度为 1 的字段。 bEntity.cKey 相对于 bEntity 位于深度 1,但 bEntity.cKey.fIdbEntity.cKey.sId 位于深度 2。

    你应该增加深度:

    @Entity @Indexed
    public class AEntity {
        @ManyToOne(optional = false)
        @IndexedEmbedded(depth = 2, includeEmbeddedObjectId = true)
        @JoinColumns(value = { @JoinColumn(name = "fk_fId", referencedColumnName = "fId"),
                @JoinColumn(name = "fk_sId", referencedColumnName = "sId") }, foreignKey = @ForeignKey(name = "fk_sub"))
        private BEntity bEntity;
    }
    

    ...或者你应该明确地包含这些字段:

    @Entity @Indexed
    public class AEntity {
        @ManyToOne(optional = false)
        @IndexedEmbedded(depth = 1, includeEmbeddedObjectId = true,
                includePaths = {"cKey.fId", "cKey.sId"})
        @JoinColumns(value = { @JoinColumn(name = "fk_fId", referencedColumnName = "fId"),
                @JoinColumn(name = "fk_sId", referencedColumnName = "sId") }, foreignKey = @ForeignKey(name = "fk_sub"))
        private BEntity bEntity;
    }
    

    【讨论】:

    • 深度为2时不再显示错误。但是尽管数据库中存在数据,但查询返回null。第一次启动应用程序时它返回null,但是当我重新启动应用程序时它返回数据。
    • 我认为问题出在索引的构建上。我添加了这一行。我添加了这个 ligne fullTextEntityManager.createIndexer().startAndWait(); 它现在第一次工作,但需要很长时间才能获取数据。还有其他解决方案吗?
    • fullTextEntityManager.createIndexer().startAndWait(); 构建索引。可以将其视为初始化数据库的 SQL 脚本的等价物。这不是您应该为每个查询做的事情。你应该只做一次,第一次启动你的应用程序。最简单的方法通常是在管理控制台中放置一个按钮。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-11
    • 1970-01-01
    • 2012-10-02
    • 2012-05-07
    • 1970-01-01
    相关资源
    最近更新 更多