【问题标题】:Can you help to understand how to use JOIN with spring-repository?您能帮助了解如何将 JOIN 与 spring-repository 一起使用吗?
【发布时间】:2025-12-21 13:35:16
【问题描述】:

我想了解如何将 JOIN 与 JPA-spring-repositories 一起使用。 有两张表 Man 和 Car

Man
varchar(25) manId primary key not null
varchar(25) name
varchar(25) surname
varchar(25) modelCar

Car
varchar(25) carId primary key not null,
varchar(25) color,
varchar(25) model;

和可视化:

    Man
    mainId   name     surname   modelCar
    =====================================
    111-1    Natasha  Smith     reno-123
    111-2    Maria    John      mazda-214


    Car
    carId      color     model
    ============================
    as-aw    red       reno-123
    os-dz    black     mazda-214
    sa-aa    yeallow   porche-1

关系是一对一的

我的实体是

@Entity
@Table
@Getter @Setter @NoArgsConstructor 
class ManRecord{
   private String manId;
   private String surname;
   private String modelCar;
}

@Entity
@Table
@Getter @Setter @NoArgsConstructor
class CarRecord{
   private String carId;
   private String color;
   private String model;
}

所以,我需要编写 JPA-repositories 来执行 join 的结果: 姓名、姓氏和汽车颜色:

select m.name, m.surname, c.color from Man m left join Car c on m.modelCar=c.model;

你能帮帮我吗?

我试过了

@Repository
public interface ManRepository extends CrudRepository<Man, String>{
   @Query("select m.name, m.surname, c.color from Man m left join Car c on m.modelCar=c.model", nativeQuery=true)
   List<Object> agregateData();
}

但我不想只得到对象。

而且,我用@OneToOne 尝试过某人,但这对我没有帮助

【问题讨论】:

    标签: java database spring jpa


    【解决方案1】:

    首先,通过car 的模型加入这些实体并不是一个好主意 - 每个man 都可以拥有任何汽车,因此这种加入不具有代表性。最好的方法是将r_man_id 添加到Car 表中。它将允许您识别汽车的所有者。 之后,您可以在它们之间添加单向@OneToMany 关系:

    @Entity
    @Table
    @Getter @Setter @NoArgsConstructor 
    class ManRecord{
    
        @JoinColumn(name = "r_man_id", referencedColumnName = "manId")
        private List<CarRecord> cars = new ArrayList<>();
    
        private String manId;
        private String surname;
        private String modelCar;
    }
    
    @Entity
    @Table
    @Getter @Setter @NoArgsConstructor
    class CarRecord{
        private String carId;
        private String color;
        @Column(name="r_man_id")
        private Long refManId;
        private String model;   
    }
    

    然后创建一个你需要的模型:

    class ManWithCarObject {
        String name;
        String surename;
        String color;
    
        /**
        * Default
        **/
        public ManWithCarObject(){      
        }
    
        public ManWithCarObject(String name, String surename, String color) {
            this.name = name;
            this.surename = surename;
            this.color = color;
        }
    
        // other methods
    }
    

    然后回购将是:

    @Repository
    public interface ManRepository extends CrudRepository<Man, String>{
       @Query("select new com.contoso.model.ManWithCarObject(m.name, m.surename, m_c.color) from ManRecord m inner join m.cars m_c where m.manId = m_c.refManId")
       List<ManWithCarObject> agregateData();
    }
    

    【讨论】:

    • 谢谢,我会试试的。我需要@OneToOne,因为我只查看了示例表,并且在其他应用程序数据库中有几个外部表。
    • 我需要在任何字段或新 id 中添加@Id 吗?
    • @id 必须只为标识列添加,而不是为所有列添加
    • 谈到@oneToOne - 由于我在答案开头的解释,这绝对不是选项 - 不能保证给定的人不会出现另一辆车
    • @Query("select new com.contoso.model.ManWithCarObject(m.name, m.surename, m_c.color) from ManRecord m inner join m.cars m_c where m.manId = m_c. refManId") List agregateData();返回 Failed to convert from type [java.lang.Object[]] to type ManWithCarObject