You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建支持两表联查取数的Entity类与Repository

两表联查场景的Entity与Repository实现方案

你当前执行的是city和countrylanguage基于CountryCode字段的内连接查询,以下是Spring Data JPA栈下的可落地实现方式:

1. 编写单表映射实体类

两个表没有直接的外键主从依赖,均通过CountryCode关联国家维度表,先分别编写和表结构一一对应的实体:

  • 城市表实体City
import jakarta.persistence.*;

@Entity
@Table(name = "city")
public class City {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "Name")
    private String name;

    @Column(name = "CountryCode")
    private String countryCode;

    @Column(name = "District")
    private String district;

    @Column(name = "Population")
    private Integer population;

    // 空参构造、全参构造、getter、setter直接用IDE生成即可
    public City() {}
}
  • 国家语言表实体CountryLanguage
    countrylanguage以CountryCode+Language为联合主键,用内嵌主键实现映射:
import jakarta.persistence.*;
import java.io.Serializable;

// 联合主键类
@Embeddable
public class CountryLanguageId implements Serializable {
    @Column(name = "CountryCode")
    private String countryCode;
    @Column(name = "Language")
    private String language;

    // 必须实现空参构造、equals、hashCode方法,直接用IDE生成即可
    public CountryLanguageId() {}
}

@Entity
@Table(name = "countrylanguage")
public class CountryLanguage {
    @EmbeddedId
    private CountryLanguageId id;

    @Column(name = "IsOfficial")
    private String isOfficial;

    @Column(name = "Percentage")
    private Float percentage;

    // 空参构造、get/set用IDE生成即可
    public CountryLanguage() {}
}

2. 定义联查结果接收对象

你写的SQL返回两表全量字段,单表实体无法承接全量数据,编写VO类做结果映射:

public class CityWithLanguageVO {
    // 城市表字段
    private Integer cityId;
    private String cityName;
    private String countryCode;
    private String district;
    private Integer cityPopulation;
    // 国家语言表字段
    private String language;
    private String isOfficial;
    private Float languagePercentage;

    // 全参构造必须保留,参数顺序要和SQL查询返回的字段顺序严格一致
    public CityWithLanguageVO(Integer cityId, String cityName, String countryCode, String district, Integer cityPopulation, String language, String isOfficial, Float languagePercentage) {
        this.cityId = cityId;
        this.cityName = cityName;
        this.countryCode = countryCode;
        this.district = district;
        this.cityPopulation = cityPopulation;
        this.language = language;
        this.isOfficial = isOfficial;
        this.languagePercentage = languagePercentage;
    }

    // getter、setter用IDE生成即可
}

3. 实现Repository数据访问层

先编写两个单表的基础Repository,承接单表增删改查能力:

import org.springframework.data.jpa.repository.JpaRepository;

public interface CityRepository extends JpaRepository<City, Integer> {
    // 自定义联查方法写在这里
}

public interface CountryLanguageRepository extends JpaRepository<CountryLanguage, CountryLanguageId> {
}

在CityRepository中添加自定义联查方法,绑定你写的查询逻辑:

import org.springframework.data.jpa.repository.Query;
import java.util.List;

public interface CityRepository extends JpaRepository<City, Integer> {
    @Query(value = "select city.ID, city.Name, city.CountryCode, city.District, city.Population, countrylanguage.Language, countrylanguage.IsOfficial, countrylanguage.Percentage from city join countrylanguage on city.CountryCode=countrylanguage.CountryCode order by city.ID", nativeQuery = true)
    List<CityWithLanguageVO> listCityWithLanguage();
}

注意:不要直接在自定义查询里写select *,两个表存在CountryCode同名字段,会出现字段重名冲突;手动指定查询字段、和VO构造器参数顺序对齐,可以完全避免映射错位、字段丢失问题。如果不想写VO,也可以用List<Map<String,Object>>作为返回值,但是类型不安全,正式项目不推荐。

如果要做对象模型层面的关联查询,也可以在City实体中通过countryCode字段配置@OneToMany关联CountryLanguage,但因为两个表没有直接指向对方主键的外键,这种配置很容易出现懒加载失效、结果笛卡尔积问题,直接写原生SQL映射VO是最稳妥的实现方式。


内容的提问来源于stack exchange,提问作者Rooban k

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 16:21:31