基于JPA规范的spring-data-jpa面向对象的查询方法举例

本文详细介绍了如何使用Spring Data JPA的面向对象查询方法,通过实现Specification接口来创建复杂的查询条件,进而高效地从数据库中获取所需数据。以一个具体的例子展示了如何将查询条件转化为SQL语句,并说明了如何对查询结果进行排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spring-data-jpa是一款基于JPA规范开发的持久层框架,与hibernate类似,spring-data-jpa也基于JPA的规范提供了自己的面相对象的查询方法。


在org.springframework.data.jpa.repository.JpaSpecificationExecutor接口中提供了一个List<T> findAll(Specification<T> spec)的方法,我们在使用面相对象的查询方法时候需要实现Specification接口,Specification接口的定义如下:

public interface Specification<T> {

	/**
	 * Creates a WHERE clause for a query of the referenced entity in form of a {@link Predicate} for the given
	 * {@link Root} and {@link CriteriaQuery}.
	 * 
	 * @param root
	 * @param query
	 * @return a {@link Predicate}, must not be {@literal null}.
	 */
	Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
}

可以看出Specification接口需要实现toPredicate方法,熟悉JPA的朋友应该都清楚,这三个参数都属于JPA的规范,如果我们需要对单个表进行相对复杂的查询操作,就可以使用List<T> findAll(Specification<T> spec)的查询方法,我在这里举例使用数据库表格脚本是:

CREATE TABLE `NewTable` (
`call_prefix_id`  int(11) NOT NULL AUTO_INCREMENT COMMENT '前缀字冠' ,
`call_prefix_name`  varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '字冠名称' ,
`call_prefix_code`  varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字冠前缀' ,
`call_type_id`  int(5) NOT NULL COMMENT '呼叫类型字冠ID' ,
PRIMARY KEY (`call_prefix_id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
AUTO_INCREMENT=5
ROW_FORMAT=COMPACT
;
entity类:

@Entity
@Table(name = "call_prefix_info_table")
public class CallPrefixInfoTable implements java.io.Serializable {

	/**
	 * @Fields serialVersionUID : TODO
	 */
	private static final long serialVersionUID = 1L;
	// Fields

	private Integer callPrefixId;
	private String callPrefixName;
	private String callPrefixCode;
	private Integer callTypeId;

	// Constructors

	/** default constructor */
	public CallPrefixInfoTable() {
	}

	/** minimal constructor */
	public CallPrefixInfoTable(String callPrefixCode, Integer callTypeId) {
		this.callPrefixCode = callPrefixCode;
		this.callTypeId = callTypeId;
	}

	/** full constructor */
	public CallPrefixInfoTable(String callPrefixName, String callPrefixCode,
			Integer callTypeId) {
		this.callPrefixName = callPrefixName;
		this.callPrefixCode = callPrefixCode;
		this.callTypeId = callTypeId;
	}

	// Property accessors
	@Id
	@GeneratedValue
	@Column(name = "call_prefix_id", unique = true, nullable = false)
	public Integer getCallPrefixId() {
		return this.callPrefixId;
	}

	public void setCallPrefixId(Integer callPrefixId) {
		this.callPrefixId = callPrefixId;
	}

	@Column(name = "call_prefix_name", length = 50)
	public String getCallPrefixName() {
		return this.callPrefixName;
	}

	public void setCallPrefixName(String callPrefixName) {
		this.callPrefixName = callPrefixName;
	}

	@Column(name = "call_prefix_code", nullable = false, length = 30)
	public String getCallPrefixCode() {
		return this.callPrefixCode;
	}

	public void setCallPrefixCode(String callPrefixCode) {
		this.callPrefixCode = callPrefixCode;
	}

	@Column(name = "call_type_id", nullable = false)
	public Integer getCallTypeId() {
		return this.callTypeId;
	}

	public void setCallTypeId(Integer callTypeId) {
		this.callTypeId = callTypeId;
	}
}

mvc使用的查询model:

public class CallPrefixModel {
	
	private String prefixName;
	private String prefixCode;
	private String callTypeId;
	
	public CallPrefixModel() {
		super();
	}

	public CallPrefixModel(String prefixName, String prefixCode,
			String callTypeId) {
		super();
		this.prefixName = prefixName;
		this.prefixCode = prefixCode;
		this.callTypeId = callTypeId;
	}

	public String getPrefixName() {
		return prefixName;
	}

	public void setPrefixName(String prefixName) {
		this.prefixName = prefixName;
	}

	public String getPrefixCode() {
		return prefixCode;
	}

	public void setPrefixCode(String prefixCode) {
		this.prefixCode = prefixCode;
	}

	public String getCallTypeId() {
		return callTypeId;
	}

	public void setCallTypeId(String callTypeId) {
		this.callTypeId = callTypeId;
	}
}

spring-data-jpa的dao层不需要我们自己写实现类,只需要提供接口,想要使用面向对象的查询方法,dao接口需要继承org.springframework.data.jpa.repository.JpaSpecificationExecutor接口,本文实例的dao接口:

@Repository("callPrefixInfoTableDao")
public interface CallPrefixInfoTableRepository extends
		JpaRepository<CallPrefixInfoTable, Integer>,JpaSpecificationExecutor<CallPrefixInfoTable> {
	
}
其中在service层中,我们需要实现查询方法的定义,service层的代码:

@Service
public class CallPrefixService {

	@Resource
	private CallPrefixInfoTableRepository callPrefixInfoTableDao;
	
	/**
	 * 
	 * 根据查询条件查询字冠信息
	 * @param @param model
	 * @return List<CallPrefixInfoTable>  
	 * @author QianLei
	 * @date 2015年9月25日
	 */
	public List<CallPrefixInfoTable> findCallPrefixs(final CallPrefixModel model) {
		List<CallPrefixInfoTable> infos = callPrefixInfoTableDao.findAll(new Specification<CallPrefixInfoTable>(){
			@Override
			public Predicate toPredicate(Root<CallPrefixInfoTable> root,
					CriteriaQuery<?> query, CriteriaBuilder cb) {
				Path<String> namePath = root.get("callPrefixName");
				Path<String> codePath = root.get("callPrefixCode");
				Path<Integer> callTypePath = root.get("callTypeId");
				List<Predicate> predicatesList = new ArrayList<Predicate>();
				predicatesList.add(cb.like(namePath, "%" + model.getPrefixName() + "%"));
				predicatesList.add(cb.like(codePath, "%" + model.getPrefixCode() + "%"));
				String[] typeIdsStr = model.getCallTypeId().split(",");
				List<Integer> typeIds = new ArrayList<Integer>();
				for(String typeId : typeIdsStr){
					typeIds.add(Integer.valueOf(typeId));
				}
				predicatesList.add(callTypePath.in(typeIds));
				query.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
				return query.getRestriction();
			}
		});
		return infos;
	}
}
只需要在controller中调用service的findCallPrefixs()方法,传入查询对象,就可以以面相对象的方式进行查询操作。例子中的查询操作转换成sql语句为:

select  * from CallPrefixInfoTable where callPrefixName like `%参数%` and callPrefixCode like `%参数%` and callTypeId in (int,int,int);

同时还可以调用query的排序方法对查询结果进行排序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值