项目中,jpa对于简单的数据库操作很方便,但如果多表关联动态查询时,需要自己去写SQL语句拼接查询条件,以下为本人学习的例子。
类似于这种多条件动态查询:
项目用的是springboot 2.1.0.RELEASE版本以及spring-boot-starter-data-jpa,其中spring-boot-starter-data-jpa底层已经依赖了hibernate-core5.3.7.Final,数据库用的是postgresql。
这里pom.xml和properties配置文件省略。
由于不能直接spring-data-jpa的Repository调用接口,所以得获取操作数据层的入口,详情请查看springBoot获取jpa的sessionFactory。
一.实体类(直接从工程复制粘贴过来的,有错可以自己解决,@Data为lombok工具的注解,自动生成getter/setter以及构造方法等)
**
* 商品表
*/
@Entity
@Table(name = "t_goods ")//heibernate自动生成数据库表
@Data
public class TGoods implements Serializable {
//这里关联两张表
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@ApiParam("自增列")
private int id;
private String goodsId;//商品id
private String goodsName;//商品名称
}
**
* 商品规格表
*/
@Entity
@Table(name = "t_goods_spec ")
@Data
public class TGoodsSpec implements Serializable {
//这里关联两张表
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@ApiParam("自增列")
private int id;
private String goodsSpecId;//商品规格Id
private String goodsName;//商品规格名称
private String goodsId;//商品id
}
**
* 库存表
*/
@Entity
@Table(name = "t_stock_statistics ")
@Data
public class TStockStatistics implements Serializable {
//这里关联两张表
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@ApiParam("自增列")
private int id;
private String goodsId;//商品id
private String goodsSpecId;//商品规格Id
private long totalAmount;//现有库存
}
二.测试JUnit代码
@RunWith(SpringRunner.class)
@SpringBootTest(classes = 对应的启动类.class)
public class ProviderApplicationTests {
@PersistenceContext//jpa的数据库操作类
private EntityManager entityManger;
@Test
public void test() throws Exception{
String ids = "2,3";
String supplier = "美的";
String goodsName = "空调";
String goodsSpecName = "1匹";
String sql = "select t1.goods_id goodsId,t1.id id,t2.goods_name goodsName,t1.goods_spec_id goodsSpecId,t3.goods_spec_name goodsSpecName from t_stock_statistics t1 join t_goods t2 on t1.goods_id = t2.goods_id join t_goods_spec t3 on t3.spec_id = t1.goods_spec_id where 1=1";
// 拼接动态查询条件的sql语句
// 中的:supplier表示传进来的参数的名称
// 另外一种传参方式是其中1代表的是参数传进来的顺序号,比如 nativeQuery.setParameter(1, “美的”);
Mapmap = new HashMap<>();
if(StringUtil.isNullOrEmpty(ids)){// 这里不把id作为查询条件
sql += " and t1.id in (:ids)";
map.put("ids",ids);
}
if(!StringUtil.isNullOrEmpty(supplier)){
sql += " and t1.supplier = :supplier";
map.put("supplier",supplier);
}
if(!StringUtil.isNullOrEmpty(goodsName)){
sql += " and t2.goods_name = :goodsName";
map.put("goodsName",goodsName);
}
if(!StringUtil.isNullOrEmpty(goodsSpecName)){
sql += " and t3.goods_spec_name = :goodsSpecName";
map.put("goodsSpecName",goodsSpecName);
}
sql += " order by id DESC";
Query nativeQuery = entityManger.createNativeQuery(sql);
// 把参数传进去
for (String key:map.keySet()
) {
if(key.equals("ids")){
ListidList = new ArrayList<>();
String[] split = map.get(key).toString().split(",");
for (String value:split
) {
idList.add(Integer.valueOf(value));
}
nativeQuery.setParameter("ids", idList);
} else {
nativeQuery.setParameter(key, map.get(key));
}
}
// 对查询出来的结果进行处理
// 有三种处理方式,Transformers.ALIAS_TO_ENTITY_MAP为其中一种,另一个相似的是Transformers.TO_LIST
nativeQuery.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
List> resultList = nativeQuery.getResultList();
for (Mapmap1 :resultList
) {
System.out.println(map1);
}
// 这是第三种,Transformers.aliasToBean(StockStatisticsVO.class)意思为把查出来的结果转换成一个StockStatisticsVO实体类
/*nativeQuery.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(StockStatisticsVO.class));
ListresultList = nativeQuery.getResultList();
for (StockStatisticsVO svo:resultList
) {
System.out.println(svo.toString());
}*/
}
}
附StockStatisticsVO实体类
/**
* 仓库出入库VO
*/
@Data
public class StockStatisticsVO implements Serializable {
//构造方法(无参)必须
//VO类有的属性,sql查询语句必须有对应的返回字段值,顺序不分
//postgresql返回字段名不分大小写,统一小写
private int id;
private String goodsid;//商品id
private String goodsname;//商品名称
private String goodsspecid;//商品规格Id
private String goodsspecname;//商品规格名称
public StockStatisticsVO() {
}
}
测试结果: