【问题标题】:Many to one relation beetween 3 entities3个实体之间的多对一关系
【发布时间】:2021-04-14 10:42:57
【问题描述】:

在我的 springboot 应用程序中,我有这 3 个实体:

@Entity
public class Process {
    @Id
    private Long Id;

    @ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
    @JoinColumn(name = "input_id")
    private Input input;
    ...
}

@Entity
public class Input{
    @Id
    private Long Id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "template_id")
    private Template template;
    ...
}

@Entity
public class Template{
    @Id
    private Long Id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "template_id")
    private Template template;
    
    private String name;    
    ...
}

总之,Process 对 Input 有一个 FK,Input 对 Template 有一个 FK。

我想过滤模板具有特定名称的进程。这是我要执行类似操作的 SQL:

    select
        *
    from
        process p 
    left outer join
        input i 
            on p.input_id=i.id 
    left outer join
        template t 
            on i.template_id=t.id 
    where
        t.name='templateName'

这是我目前在我的流程实体中访问模板的内容:

    @ManyToOne
    @JoinTable(name = "Input",
            joinColumns = {@JoinColumn(table = "Input", referencedColumnName = "id")},
            inverseJoinColumns = {
                    @JoinColumn(name = "template_id", referencedColumnName = "id", table = "Template")})
    private Template template;

这是我的 ProcessRepository 类,我现在可以在其中访问所需的查找方法:

@Repository
public interface ProcessRepository extends PagingAndSortingRepository<Process, Long> {
    ...
    List<Process> findByTemplateNameEquals(String templateName);
    ...
}

当我执行 findByTemplateNameEquals 方法时,我会检索流程和一个模板。但是我得到的结果并不是我所期望的。 我启用了 sql 日志记录,这是真正执行的查询(我隐藏了列,这里不重要):

    select
...
    from
        process process0_ 
    left outer join
        input process0_1_ 
            on process0_.id=process0_1_.id 
    left outer join
        template template1_ 
            on process0_1_.template_id=template1_.id 
    where
        template1_.name=?

Process 和 Input 之间的连接存在一个问题。它执行

from
  process process0_ 
left outer join
  input process0_1_ 
  on process0_.id=process0_1_.id

而不是

from
  process process0_ 
left outer join
  input process0_1_ 
  on process0_.input_id=process0_1_.id

我不明白为什么它使用进程的 PK 而不是 FK 来输入。 我尝试了几件事来解决这个问题:

  1. 在joinColumns中添加name="input_id" = {​​@JoinColumn(... 但不是替换FK,而是替换输入的PK=>执行过程中失败
  2. 将 joinColumns = {@JoinColumn(...) 中的 referencedColumnName 替换为“input_id”,但启动失败。
  3. 在多个位置(直接在@JoinTable、@JoinColumn 甚至 Input 输入属性的 @JoinColumn 中)配置了 @ForeignKey(name = "input_id"),但没有任何变化。

我还指出,joinColumns = {@JoinColumn(table = "Input", referencedColumnName = "id")} 不是必需的,因为如果我删除它,我也会有同样的行为。

有人可以帮我解决这个问题吗?

在此先感谢

【问题讨论】:

    标签: java hibernate spring-data-jpa


    【解决方案1】:

    我认为在Process 级别声明template 字段可能是不必要的,因为您已经与Input 建立了关系,而且肯定容易出错。

    无论如何,如果有必要,我会用类似的东西来定义字段:

    @ManyToOne
    @JoinTable(
      name = "Input",
      joinColumns = { @JoinColumn(name = "input_id")},
      inverseJoinColumns = {@JoinColumn(name = "template_id")}
    )
    private Template template;
    

    请,验证代码。

    话虽如此,如果您只需要通过name 获取与某个template 关联的存储库,您可以尝试在您的find 方法中浏览对象层次结构。请尝试:

    @Repository
    public interface ProcessRepository extends PagingAndSortingRepository<Process, Long> {
        ...
        List<Process> findByInput_Template_Name(final String templateName);
        ...
    }
    

    【讨论】:

    • 您好 jccampanero,感谢您的回复,我确认 List findByInput_Template_Name(final String templateName);给我我想要的:)。我对此进行了一些研究,并在文档中找到了这个(小)部分。 :docs.spring.io/spring-data/jpa/docs/current/reference/html/…。另外,我想过滤 createdDate。这是要使用的函数: List findByCreatedDateGreaterThanEqualAndCreatedDateLessThanEqualAndInput_Template_Name(Date startDate, Date endDate, String templateName);
    • 欢迎您@ElliottVentura。太好了,我很高兴知道答案很有帮助,并且您可以根据进一步的要求改进代码。如果您需要进一步的帮助,请随时与我联系。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-05
    • 2020-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多