【问题标题】:Spring Data JPA Specification search for property in nested collectionSpring Data JPA 规范搜索嵌套集合中的属性
【发布时间】:2020-11-23 13:27:41
【问题描述】:

假设我至少有两个实体。

@Entity
public class Process {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true)
    private String name;

    @ManyToAny(
            metaColumn = @Column(name = "node_type"),
            fetch = FetchType.LAZY
    )
    @AnyMetaDef(
            idType = "long", metaType = "string",
            metaValues = {
                    @MetaValue(targetEntity = Milestone.class, value = MILESTONE_DISC),
                    @MetaValue(targetEntity = Phase.class, value = PHASE_DISC)
            }
    )
    @Cascade({org.hibernate.annotations.CascadeType.ALL})
    @JoinTable(
            name = "process_nodes",
            joinColumns = @JoinColumn(name = "process_id", nullable = false),
            inverseJoinColumns = @JoinColumn(name = "node_id", nullable = false)
    )
    private Collection<ProcessNode> nodes = new ArrayList<>();

    ...
}

@Entity
@ToString
@DiscriminatorValue(MILESTONE_DISC)
public class Milestone implements ProcessNode {


    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Collection<ResultDefinition> results;

    @ToString.Exclude
    @ManyToOne(fetch = FetchType.LAZY)
    @Transient
    private Process process;

...
}

现在我想使用 spring data jpa 规范来查找(所有)具有名为“S5”的里程碑的进程。

请注意,Milestone 是一个 ProcessNode,还有另一个名为 Phase 的实体也是一个 ProcessNode。这些可以包含在我的流程实体的“节点”集合中。

我试着写这样的东西:

    public static Specification<Process> hasMilestoneWithName(final String milestoneName) {
    return (Specification<Process>) (root, query, criteriaBuilder) -> {
        Path<?> namePath = root.join("nodes").get("name");
        return criteriaBuilder.equal(namePath, milestoneName);
    };
}

这不起作用,但会抛出:

原因:java.lang.IllegalArgumentException:无法在此 ManagedType [com.smatrics.dffs.processservice.model.entities.Process] 上找到具有给定名称 [nodes] 的属性

我真的不知道如何使用 API。示例通常指的是由 IDE 或 maven 生成的元模型,但我真的不希望有任何静态生成的资源。请在没有生成元模型的情况下使用 spring-data-jpa 规范帮助我解决这个问题。

如果你能帮我写 hql 那就太棒了。

谢谢!

【问题讨论】:

    标签: java spring hibernate spring-data-jpa criteria


    【解决方案1】:

    我会建议一个更简单的替代方案,自下而上:

    • 使用name=S5 加载Milestone 实体:findByName("S5")
    • 为每个Milestone 返回Process
    • 过滤掉重复项

    或者您甚至可以保存一些 SQL 查询,方法是不返回 Milestone 实体,而只返回每个 MilestoneProcess 的 ID,然后通过 ID 列表加载 Process 节点:

    (本机)SQL 等效项是

    select *
    from process
    where id in (
      select process_id
      from milestone
      where name = 'S5'
    )
    

    不管我的解决方案如何,您的 join 对我来说看起来并不完全正确,但我无法指出问题所在 - 也许 JPA 元模型上还有其他方法返回 CollectionJoin?不确定。可能是因为 @ManyToAny 不是 JPA 标准,所以 JPA 标准 API 无法将 nodes 识别为有效的“可连接”字段。

    【讨论】:

    • 感谢您的回答。我不想为里程碑创建存储库/服务,因为它只是更大聚合(过程)的一部分。在我看来,本机查询也不起作用,因为 process_id 没有存储在里程碑中(它是暂时的,也应该是,因为映射在表 process_nodes 中)。 @ManyToAny 不是标准的 JPA,您可能是对的,但据我所知,没有更好的方法来映射关系,因为在 JPA 中没有支持多态的功能(?)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-13
    • 2013-07-25
    • 2016-07-22
    • 1970-01-01
    • 1970-01-01
    • 2016-01-02
    • 2016-02-17
    相关资源
    最近更新 更多