JPA⾃定义原⽣sql查询踩坑现场
JPA⾃定义原⽣sql查询踩坑现场
最近在做⼀个⼩程序的java后台管理系统,操作数据库要求采⽤Spring Data API,之前没有使⽤过,项⽬⽐较赶,所以就简单了解了⼀下操作步骤,⼯作原理。这⽅⾯的详细介绍⽹上很多,以后时间充裕再从头细过⼀遍。⽬测简直是个神器呀~~
Spring Data JPA是Spring Data家族的⼀部分,可以轻松实现基于JPA的存储库。 此模块处理对基于JPA的数据访问层的增强⽀持。 它使构建使⽤数据访问技术的Spring驱动应⽤程序变得更加容易。
但是坑⽐的事情出现了---------------
这是我的店铺实体类,需要⼀条距离diatance字段,这个当然不能存在数据库⾥:
@Entity
@Getter
@Setter
@Table(name="shop")
@NoArgsConstructor
@AllArgsConstructor
public class Shop implements Serializable {
@Id
@JoinColumn(name ="id")
@GeneratedValue(strategy = GenerationType.IDENTITY) @NotNull(groups = Shop.Update.class)
private Long id;
@JoinColumn(name ="channel_en")
private String channel_en;
@JoinColumn(name ="highlevelcategory_en")
private String highlevelcategory_en;
@JoinColumn(name ="subcategory_en")
private String subcategory_en;
@JoinColumn(name ="name")制作查询类小程序
private String name;
@JoinColumn(name ="star")
private String star;
@JoinColumn(name ="star_nr")
private BigDecimal star_nr;
@JoinColumn(name ="address")
private String address;
@JoinColumn(name ="latitude")
private BigDecimal latitude;
@JoinColumn(name ="longitude")
private BigDecimal longitude;
@JoinColumn(name ="phonecall")
private String phonecall;
@JoinColumn(name ="averagecost")
private Integer averagecost;
@JoinColumn(name ="businesshours")
private String businesshours;
@JoinColumn(name ="environmentscore")
private BigDecimal environmentscore;
@JoinColumn(name ="servicescore")
private BigDecimal servicescore;
@JoinColumn(name ="tastescore")
private BigDecimal tastescore;
@Column(name ="openclose",nullable =false)
@NotNull
private Boolean openclose;
@Column(name ="create_time")
@CreationTimestamp
private Timestamp createTime;
/
/***************************数据库中不存在该字段
private Double distance;
//***************************
//    private List<Picture> photos;
public @interface Update {}
}
现在我需要⼀番操作后得到distance,并直接封装给前台。同时实现动态查询以及分页和排序。
⼀个⼗分简单的需求-------但是我突然搞不定了。。。。。。
最开始打算这样做————再封装⼀层ShopDTO给前台,中间的数据(关注Isattention,距离distance⽤⽅法塞进去)1.实现JpaRepository的对应Shop接⼝(符合JPA规范)
public interface ShopRepository extends  JpaRepository<Shop, Long>,JpaSpecificationExecutor<Shop>{
}
2.Mapper接⼝(Shop(从数据库中查并持久化的数据)—>ShopDTO(给前台的数据))
@Mapper(componentModel ="spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface ShopMapper  extends BaseMapper<ShopDTO, Shop>{
}
3. JPA著名的操作⽅式findall(传⼊条件查询对象,以及追加分页功能的pageable),简直⽅便的飞起~~~
~
public Object queryAll(ShopQueryCriteria criteria, Pageable pageable)throws ClassNotFoundException {
JwtUser jwtUser =(JwtUser)userDetailsService.Username());
/*********************************************************/
JPA著名的操作⽅式findall(传⼊条件查询对象,以及追加分页功能的pageable),简直⽅便的飞起~~~~
/*********************************************************/
Page<Shop> page =  shopRepository.findAll((root, criteriaQuery, criteriaBuilder)-> Predicate(root,criteria,criteriaBuilder),pageable);
Page<ShopDTO> shopDto = page.map(shopMapper::toDto);
shopDto.forEach(shop ->{
//图⽚
List<Picture> photos = pictureService.Id().longValue());
shop.setPhotos(photos);
System.out.println(shop);
//是否关注
Attention attention = attentionRepository.Id(), Id().longValue());
if(attention == null){
shop.setIsattention(false);
}else{
shop.setIsattention(true);
}
//距离--------------------------
Latitude()!=null&&Longitude()!=null){
double latitude = Latitude().doubleValue();
double longitude = Longitude().doubleValue();
double distance = Distance(latitude, longitude, Latitude().doubleValue(), Longitude().doubleValue());
if(distance<1){//⼩于1公⾥
shop.setFar_from(String.format("%.2f", distance*1000)+" m");//保留两位⼩数
}else{
shop.setFar_from(String.format("%.2f", distance)+" km");
}
//                shop.setDistance(distance);
}
});
Page(shopDto);
}
如愿所偿,前台得到数据。
然⽽------------------------
因为距离DiStance不在数据库表对应类中,pageable提供的简单排序⽅法实现不了,哎哟我去。。。。。。。
所以打算⽤ShopRepository ⾥追加原⽣sql的⽅式来实现试试。。
1.把distance作为别名进⾏sql查询,并且添加nativeQuery = true(为了实现分页)
public interface ShopRepository extends  JpaRepository<Shop, Long>,JpaSpecificationExecutor<Shop>{
@Query(value ="select * , "+
"ROUND( "+
"        6378137 * 2 * ASIN( "+
"            SQRT( "+
"                POW( "+
"                    SIN( "+
"                        ( "+
"                            ?1 * PI() / 180 - latitude * PI() / 180 "+
"                        ) / 2 "+
"                    ), "+
"                    2 "+
"                ) + COS( ?1 * PI() / 180) * COS(latitude * PI() / 180) * POW( "+
"                    SIN( "+
"                        ( "+
"                            ?2 * PI() / 180 - longitude * PI() / 180 "+
"                        ) / 2 "+
"                    ), "+
"                    2 "+
"                ) "+
"            ) "+
"        ) * 10000 "+
"    )/10000 AS distance "+
" FROM shop "+
"ORDER BY distance ASC",nativeQuery =true)
List<Shop>findByFarSort(BigDecimal h_latitude, BigDecimal h_longitude);
}
但是还是⽆法动态改变排序的字段,⽽且JPA优秀的动态查询也⽆法添加进去,那我要你这JPA有何⽤。。。。⼀筹莫展。。。
查了两天,依然没法⾃如的以JPA结合⾃定义Sql的⽅式解决问题。。。
太菜了。。。
时间紧迫,只好妥协,,还是打算采⽤sql拼接,看上去不聪明。。。
1.⾃定义⼀个Repository的⽅法接⼝,并且进⾏实现拓展⽅法,坑也好多。。
/**
* ⾃定义Repository的⽅法接⼝
* @author xiaowen
* @param <T> 领域对象即实体类
* @param <ID>领域对象的注解
*/
@NoRepositoryBean
public interface FindShopHasDistanceRepository<T, ID extends Serializable>{
//    @Override
Page<Shop>findAll2(ShopQueryCriteria criteria,Pageable pageable)throws ClassNotFoundException;
}
@NoRepositoryBean:确保添加了该注解的 repository 接⼝不会在运⾏时被创建实例。也就是说,使⽤了该注解的接⼝不会被单独创建实例,只会作为其他接⼝的⽗接⼝⽽被使⽤。
2.实现类,添加的查询⽅法(JPA的优势当然⽆存。。。跪求正确的解决⽅式,对包含数据库不存在的字段查询以及持久化如何优雅的结合进JPA,⼤佬们)
public class ShopRepositoryImpl<T, ID extends Serializable>implements FindShopHasDistanceRepository<T, Serializable>{
/**
* 持久化上下⽂
*/
private final EntityManager entityManager;
public ShopRepositoryImpl( EntityManager entityManager){
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。