千家信息网

JPA怎么使用nativequery多表关联查询返回自定义实体类

发表于:2025-02-04 作者:千家信息网编辑
千家信息网最后更新 2025年02月04日,这篇文章主要介绍了JPA怎么使用nativequery多表关联查询返回自定义实体类,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。JPA
千家信息网最后更新 2025年02月04日JPA怎么使用nativequery多表关联查询返回自定义实体类

这篇文章主要介绍了JPA怎么使用nativequery多表关联查询返回自定义实体类,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

JPA nativequery多表关联查询返回自定义实体类

JPA官方推荐的多表关联查询使用不便,接触的有些项目可能会使用JPA 做简单查询,Mybaits做复杂查询。所以想要寻找一种好用的解决方案。

JPA多表关联的实现方式

1.使用Specification实现映射关系匹配,如@ManyToOne等

2.使用NativeQuery等sql或hql来实现

优缺点对比

1.映射关系是hibernate的入门基础,很多人都会习惯去使用。个人不太喜欢这种方式,复用性太弱,且不灵活特别是在多表复杂业务情况下。

2.使用Specification方式需要继承JpaSpecificationExecutor接口,构造对应的方法后传入封装查询条件的Specification对象。逻辑上简单易懂,但是构造Specification对象需要拼接格式条件非常繁琐。

3.直接使用NativeQuery等方式实现复杂查询个人比较喜欢,直观且便利,弊端在于无法返回自定义实体类。需要手动封装工具类来实现Object到目标对象的反射。

使用sql并返回自定义实体类

个人比较喜欢的实现方式,不多说看代码

import org.springframework.stereotype.Repository;import javax.persistence.EntityManager;import javax.persistence.PersistenceContext;import javax.transaction.Transactional; @Repositorypublic class EntityManagerDAO {    @PersistenceContext    private EntityManager entityManager;     /**     * 人员列表排序     * @return     */    @Transactional    public List listUser(){        String sql = "select a.create_time createTime," +                "a.mobilephone phoneNum," +                "a.email email,a.uid uid," +                "a.enabled enabled," +                "c.id_number idNumber," +                " (case b.`status` when 1 then 1 else 0 end) status " +                "from tbl_sys_user a " +                "LEFT JOIN user_high_qic b on a.uid=b.u_id" +                "LEFT JOIN user_qic c on a.uid=c.uid " +                "ORDER BY status desc";         SQLQuery sqlQuery = entityManager.createNativeQuery(sql).unwrap(SQLQuery.class);        Query query =      sqlQuery.setResultTransformer(Transformers.aliasToBean(BackstageUserListDTO.class));        List list = query.list();        entityManager.clear();        return list;    }}
public class BackstageUserListDTO implements Serializable{    private static final long serid = 1L;    private String createTime;    private String phoneNum;    private String email;    private BigInteger uid;    private Integer enabled;    private String idNumber;    private BigInteger status;    //GETTER SETTER}

这样一个需求如果使用前两种方式实现,无疑会非常麻烦。使用这种方式能够直接反射需要的自定义实体类。

可以根据需求整理封装成不同的方法,加入排序,分页等。我在这里主要提供一种方便的解决思路。

JPA多表关联动态查询(自定义sql语句)

项目需求,查询需求数据需要多表链接-->根据多种条件筛选查询到的数据,在网上查了很多资料最终选择这个字符串拼接查询

类似如此动态查询

以下是本人项目中使用总结:

实体类

/** * 订单表 */@Entity@Table(name = "signedorder")@Getter@Setter@NoArgsConstructor@EntityListeners(AuditingEntityListener.class)public class SignedOrder {    @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)    @Column    private Integer id;//id    @CreatedDate    @Column(updatable = false)    private Date createTime;//创建时间    @LastModifiedDate    @Column    private Date lastModifiedTime;//修改时间    @ManyToOne(fetch = FetchType.EAGER, cascade = {            CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH    })    @JoinTable(name = "staff_signedorder", joinColumns = @JoinColumn(name =            "signedorder_id"), inverseJoinColumns = @JoinColumn(name = "staff_id"))    private Staff staff;//所属用户    @JoinColumn(name = "industry_id")    private Integer industryId;//行业Id}
/** * 用户表 */@Entity@Table(name = "staff")@Getter@Setter@NoArgsConstructorpublic class Staff {     @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)    @Column(name = "id")    private Integer id;//id    @Column(name = "name", length = 25)    private String name;//姓名    @JoinColumn(name = "city_id")    private Integer cityId;//城市id
/** * 城市表 */@Entity@Table(name = "city")@Getter@Setter@NoArgsConstructor@Accessors(chain = true)public class City {    @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)    @Column(name = "id")    private Integer id;//id    @Column(name = "name", length = 50)    private String name;//名称}//行业表和城市表一致,就不展示了

注解解释

实体类中相关注解解释:

  • @Entity: 对实体注释。任何Hibernate映射对象都要有这个注释

  • @Table: 声明此对象映射到数据库的数据表,该注释不是必须的,如果没有则系统使用默认值(实体的短类名)

  • @Getter@Setter@NoArgsConstructor:lombok提供注解,get、set方法及无参构造

  • @EntityListeners(AuditingEntityListener.class):加上此注解,时间注解@LastModifiedDate 和 @CreatedDate才可以生效

  • @Id: 声明此属性为主键

  • @GeneratedValue(strategy = GenerationType.IDENTITY):指定主键,

TABLE:使用一个特定的数据库表格来保存主键;

IDENTITY:主键由数据库自动生成(主要是自动增长型);

SEQUENCR:根据底层数据库的序列来生成主键,条件是数据库支持序列;

AUTO:主键由程序控制

  • @CreatedDate(updatable = false):创建时间时间字段,在insert的时候,会设置值;update时时间不变

  • @LastModifiedDate:修改时间段,update时会修改值

  • @ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}): 多对一,

FetchType.EAGER:立即加载, 获取关联实体;

CascadeType.MERGE: 级联更新;

CascadeType.PERSIST:级联新建;

CascadeType.REFRESH:级联刷新

  • @JoinTable: JoinColumn:保存关联关系的外键的字段;inverseJoinColumns:保存关系的另外一个外键字

  • @Column:用来标识实体类中属性与数据表中字段的对应关系

测试类

@RunWith(SpringRunner.class)@SpringBootTestpublic class SprinBootMarketingsystemApplicationTests {    @PersistenceContext//jpa的数据库操作类    private EntityManager entityManger;    @Test    public void queryDb(){       //给参数赋值        Integer cityId = 1;        Integer industryId = 2;        Integer staffId = 16;        Date startTime = DateUtil.parse("1970-01-01");//字符串时间转换为date类型        Date endTime = Calendar.getInstance().getTime();//获取系统当前时间装换为date类型                //创建SQL语句主体        StringBuffer stringBuffer = new StringBuffer("\tSELECT\n" +                "\tcount( * ) count,\n" +                "\tci.NAME cityName\n" +                "\tFROM\n" +                "\tsignedorder s\n" +                "\tLEFT JOIN staff_signedorder t ON s.id = t.signedorder_id\n" +                "\tLEFT JOIN staff sta ON t.staff_id = sta.id\n" +                "\tLEFT JOIN city ci ON sta.city_id = ci.id\n" +                "\tWHERE\n" +                "\t1 = 1");         Map map =  new HashMap<>();         //拼接动态参数        if(industryId != null){                         /*第一种给参数赋值方式             1代表传进来的参数顺序,给参数赋值nativeQuery.setParameter(1, industryId);             stringBuffer.append(" and s.industryId = ?1");*/             //industryId代表传进来的参数名称,给参数赋值nativeQuery.setParameter("industryId", industryId);             stringBuffer.append(" and s.industry_id = :industryId");             map.put("industryId",industryId);        }        if(cityId != null){            stringBuffer.append(" and ci.id = :cityId");            map.put("cityId",cityId);        }        if(staffId != null){            stringBuffer.append(" and sta.id = :staffId");            map.put("staffId",staffId);        }        if(startTime!=null && endTime!=null){            //使用这种赋值方式,时间类型需要给三个参数,参数名称,参数值,特定映射的类型TemporalType.DATE            //nativeQuery.setParameter("create_time", startTime,TemporalType.DATE);            stringBuffer.append( " and s.create_time BETWEEN :startTime and :endTime ");            map.put("startTime",startTime);            map.put("endTime",endTime);        }        Query nativeQuery = entityManger.createNativeQuery(stringBuffer.toString());        for (String key : map.keySet()) {            nativeQuery.setParameter(key, map.get(key));        }        //三种接受返回结果方式(第一种方式)        /*nativeQuery.unwrap(SQLQuery.class).setResultTransformer(Transformers.TO_LIST);        List resultList1 = nativeQuery.getResultList();        for (Object o : resultList1) {            System.out.println(o.toString());        }*/       //第二种方式和第一种方式相似        /*nativeQuery.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);        List> resultList = nativeQuery.getResultList();        for (Map map1 :resultList        ) {            System.out.println(map1);        }*/        //第三种方式:实体类接受        nativeQuery.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(TestVo.class));        List resultList = nativeQuery.getResultList();        for (TestVo svo:resultList        ) {            System.out.println(svo.toString());        }    }

打印结果

第一种方式打印结果

第二种方式打印结果

第三种方式打印结果

TestVo实体接收类

@Datapublic class TestVo {    private String cityName;//城市名字    private BigInteger count;//签单数量(必须使用BigInteger类型接受)}

感谢你能够认真阅读完这篇文章,希望小编分享的"JPA怎么使用nativequery多表关联查询返回自定义实体类"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

方式 实体 查询 参数 数据 时间 关联 数据库 对象 注解 类型 结果 城市 条件 篇文章 需求 复杂 个人 动态 名称 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 开挂链接服务器还得等72小时吗 泰坦陨落2北极星服务器网址 宁海专业软件开发公司 宁波沃幕互联网科技有限公司 html5怎么插入数据库 hp服务器故障查看 数据库软件运行卡顿 怎么获取数据库字符串中部分 广交会网络安全院士名单 长丰网络技术咨询哪家好 华中科技大学互联网作品 湖南pdu服务器电源可以定制吗 把文件加载到sql数据库 数据库根据小时分组 阿里云服务器购买不了怎么办 数据库主表与相关表怎么创建关系 域文件服务器资源管理器 mydql数据库删了如何恢复 数据库实体有哪几类 冒险岛766数据库 软件开发平台作用 江西零时网络技术 郑州网络安全科技馆如何预约 网络技术特别适用于 首都网络安全日最新 怎么查看代理服务器能不能用 湖南pdu服务器电源可以定制吗 宁海手机软件开发周期 数据库er图属性用什么图表示 观点中国网络安全
0