温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2021-11-18 13:02:49 来源:亿速云 阅读:742 作者:小新 栏目:开发技术

这篇文章主要介绍了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;   @Repository public class EntityManagerDAO {     @PersistenceContext     private EntityManager entityManager;      /**      * 人员列表排序      * @return      */     @Transactional     public List<BackstageUserListDTO> 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<BackstageUserListDTO> 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语句)

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

类似如此动态查询

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

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

实体类

/**  * 订单表  */ @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 @NoArgsConstructor public 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) @SpringBootTest public 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<String,Object> 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<Map<String, Object>> resultList = nativeQuery.getResultList();         for (Map<String, Object> map1 :resultList         ) {             System.out.println(map1);         }*/         //第三种方式:实体类接受         nativeQuery.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(TestVo.class));         List<TestVo> resultList = nativeQuery.getResultList();         for (TestVo svo:resultList         ) {             System.out.println(svo.toString());         }     }

打印结果

第一种方式打印结果

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

第二种方式打印结果

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

第三种方式打印结果

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

TestVo实体接收类

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

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

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI