使用JPA进行数据查询和关联查询
在开发中经常会使用mybatis、jpa等框架来解决O/R映射技术实现数据访问。本文主要介绍使用JPA实现数据访问。
通常在关联查询的时候,表与表之前存在的关系有
OneToOne
OneToMany
ManyToOne
ManyToMany
想要理清两个表之间的关系需要根据实际场景进行区分。在建立实体类的时候,需要知道哪一个是主体。通常情况下一对多和多对一始终是以多的一方为主体的。注解在使用中“始终在非主体的一方标记自己在主体中的名称”
基本数据查询
举例:有如下几个表的关系,表之间的ER图如下:
一对一
Student和Sore对应的关系,score类如下:
package spring.demo.security.entity.test;
import javax.persistence.*;
/**
* Created by td on 2017/10/12.
*/
@Entity
@Table(name = "score")
public class Score {
@Id
@GeneratedValue
private Integer id;
@Column(name = "chinese_score")
private Integer chinese;
@Column(name = "math_score")
private Integer math;
//通常情况下score和student中,认为studnet是主体,我们需要在sore非主体中标记他在主体中的名字
@OneToOne(mappedBy = "score")
private Student student;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getChinese() {
return chinese;
}
public void setChinese(Integer chinese) {
this.chinese = chinese;
}
public Integer getMath() {
return math;
}
public void setMath(Integer math) {
this.math = math;
}
}
student类如下:
package spring.demo.security.entity.test;
import javax.persistence.*;
/**
* Created by td on 2017/10/12.
*/
@Entity
@Table(name = "student")
public class Student {
@Id
@GeneratedValue
private Integer id;
private String username;
@OneToOne
private Score score;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
```
这两个类中需要区分谁是主体,按照场景理解Student和Score会认为Student,所以我们需要在非主体的Score中指定其在Student中的名字。
此外还可以设置级联,只需要在注解中增加参数(cascade = CascadeType.REMOVE ),必需要在主体一侧添加级联。(一般情况下不用)
#### 一对多(多对一)
以下建立student和school的关系,student是主体,下面是School类代码
```java
package spring.demo.security.entity.test;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.List;
/**
* Created by td on 2017/10/12.
*/
public class School {
@Id
@GeneratedValue
private Integer id;
private String name;
@OneToMany(mappedBy = "school")
private List students;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getStudents() {
return students;
}
public void setStudents(List students) {
this.students = students;
}
}
在Student中加入school类的,多对一关系,并且需要在school类中指定其在student中的名字
// student类中加入school类,多对一关系
@ManyToOne
private School school;
// school类中加入student并指明在student中的名字
@OneToMany(mappedBy = "school")
private List students;
多对多
Subject和Student之间是多对多的关系,下面建立subject类
package spring.demo.security.entity.test;
import javax.persistence.*;
import java.util.List;
/**
* Created by td on 2017/10/12.
*/
@Entity
@Table(name = "subject")
public class Subject {
@Id
@GeneratedValue
private Integer id;
@Column(length = 10)
private String name;
@ManyToMany(mappedBy = "subjects")
private List students;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在student类中加入
@ManyToMany
private List subjects;
基本查询
基本查询通过继承JpaRepository
public interface StudentRepository extends JpaRepository {
}
通过以上就可以进行基本的增删改查
如果JpaRepository条件不能满足需求,也可以自定义Repository自定义条件:
举例:需要通过一个学生的id 查询出这个学生所在学校的的名字
根据SimpleJpaRepository写一个Repository。
package spring.demo.security.dao;
import org.apache.commons.beanutils.ConvertUtils;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.transform.Transformers;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.transaction.Transactional;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author td
* @date 2017/10/19
*/
@Transactional
@Repository
public class CustomDao {
@PersistenceContext
EntityManager entityManager;
public List queryListEntity (String sql, Map params,Class clazz) {
Session session = entityManager.unwrap(Session.class);
SQLQuery sqlQuery = session.createSQLQuery(sql);
System.out.println(sqlQuery.toString());
if (params != null) {
for (String key:params.keySet()) {
sqlQuery.setParameter(key,params.get(key));
}
}
System.out.println(sqlQuery.toString());
sqlQuery.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
List
进行测试
// 查询一个id为1的学生学校名字
String sql = "select b.* from student a left join school b on a.school_id=b.id where a.id=:id";
// String sql = "select * from person where id = :id";
Map map = new HashMap<>();
map.put("id",1);
List schools = (List) customDao.queryListEntity(sql,map, School.class);
System.out.println(schools.get(0).getId()+"-"+schools.get(0).getName());
int count = customDao.getCountBy("select count(*) from student",null);
System.out.println(count);
关联查询
举例:需要通过学校的id查询该学生的所有信息
从以上需求可以看出需要到school和student关系的主体表中进行查询。即在student表中进行查询,通过jpa规范书写查询
//通过学生id进行查询
SysRole findById(Integer id);
//通过学校id进行关联查询角色,关联的用户表用在主体表中的表示名Student 关联的id后用_Id
//所以可以看出关联查询主要是通过_进行的
List findBySchool_Id(int id);
从例子中可以看出关联查询主要是用""符号,
如果通过本章表中id查询本章表中的role信息可以这么写:findById()
如果通过本章用户表中id查询本章表中的role信息可以这么写:findBySUser_Id()
如果既要通过本章表中的id查询有要通过用户表中的id进行查询,可以这么写:findBySUser_IdAndId()
如何还想关联更多的表可以在后面添加:And+表名字+“”+表中要查询的字段。