简体   繁体   English

3 个实体之间的多对一关系

[英]Many to one relation beetween 3 entities

In my springboot application I have these 3 entities:在我的 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;    
    ...
}

In summary, Process has an FK to Input and Input has an FK to Template.总之,Process 对 Input 有一个 FK,而 Input 对 Template 有一个 FK。

I would like to filter the processes whose template have a certain name.我想过滤模板具有特定名称的进程。 Here is the SQL I would to perform something like that:这是 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'

Here is what I currently have in my Process entity to access the template:这是我目前在我的 Process 实体中访问模板的内容:

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

Here is my ProcessRepository class, where I now have access to the desired find method:这是我的 ProcessRepository class,我现在可以访问所需的查找方法:

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

When I execute the findByTemplateNameEquals method, I retrieve the process and one template.当我执行 findByTemplateNameEquals 方法时,我检索了进程和一个模板。 But the result I got was not the one expected.但是我得到的结果并不是我所期望的。 I enabled the sql logging and here is the query really performed (I hide the columns, it is not important here):我启用了 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=?

There is one problem with the join between Process and Input. Process 和 Input 之间的连接存在一个问题。 It executes它执行

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

instead of代替

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

I don't understand why it use the PK of Process instead of the FK to Input.我不明白为什么它使用 Process 的 PK 而不是 FK 来输入。 I tried several things to solve this:我尝试了几件事来解决这个问题:

  1. Adding name="input_id" in the joinColumns = {@JoinColumn(... but instead of replacing the FK, it replaces the PK of input => failure during execution在joinColumns = {@JoinColumn(...) 中添加name="input_id" 但不是替换FK,而是替换执行过程中输入=>失败的PK
  2. replacing the referencedColumnName by "input_id" in the joinColumns = {@JoinColumn(... but it failed at launching.用 joinColumns = {@JoinColumn(...) 中的“input_id”替换 referencedColumnName,但它在启动时失败。
  3. Configuring a @ForeignKey(name = "input_id") at several places (directly in the @JoinTable, in the @JoinColumn and even in the @JoinColumn of the Input input attribute ) but there was no change.在多个位置(直接在@JoinTable、@JoinColumn 甚至 Input 输入属性的 @JoinColumn 中)配置 @ForeignKey(name = "input_id") 但没有任何变化。

I also remarked that the joinColumns = {@JoinColumn(table = "Input", referencedColumnName = "id")} was not necessary, because I have the same behaviour if I remove it.我还注意到 joinColumns = {@JoinColumn(table = "Input", referencedColumnName = "id")} 不是必需的,因为如果我删除它,我会有相同的行为。

Could someone help me on this?有人可以帮我吗?

Many thanks in advance提前谢谢了

I think the declaration of the template field at the Process level is probably unnecessary because you already have the relationship with Input , and certainly error prone.我认为在Process级别声明template字段可能是不必要的,因为您已经与Input有关系,而且肯定容易出错。

In any case, if necessary, I would define the field with something like that instead:无论如何,如果有必要,我会用类似的东西来定义该字段:

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

Pease, verify the code. Pease,验证代码。

Having said that, if you only need to obtain the repositories associated with a certain template by name you can try to navigate through the object hierarchy in your find method.话虽如此,如果您只需要按name获取与某个template关联的存储库,您可以尝试在您的find方法中浏览 object 层次结构。 Please, try:请试试:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM