前两篇介绍了一对多和多对一的单向关联,而且前几篇发帖时间都比较紧凑,由于春节期间和收假这段时间都在帮公司的培训中心架构开发一个在线考试系统,所以就耽搁了,不好意思。
那么言归正传,本篇介绍一对多,多对一的双向关联,既然是双向关联,那么一对多和多对一其实是一个意思。首先来构造一个场景,实际应用场景就用前两天开发的在线考试系统的一个部分,是这样的:实体(试卷),有如下属性:Id,名称(name),标准答案(answers),试题列表(Questions);实体(试题),有如下属性:Id,题干内容(name),所属试卷(QuestionnaireId)。
一份试卷有多个试题,但是一个试题只能属于一份问卷,一对多的关系没问题,需求还有,要根据试卷找到包含的所有试题;根据试题找到所属的试卷,那么就需要建立双向关联了。
下面我们看数据库表结构:
表结构的图虽然和单向关联没区别,也反应了一个规律:外键在多方。在本例中,t_question表是多的一方,表中有一个字段questionnaireId作为外键指向了t_questionnaire表,并且参考了t_questionnaire表的id这个字段。还有一个规律就是双向关联必须设置mappedBy属性。
下面我们看实体类的书写:
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/*
* author
* 试卷
* */
@Entity
@Table(name="t_questionnaire")
public class Questionnaire {
private Integer id;
private String name;
private String answers;
private List<Question> questions = new ArrayList<Question>();
public Questionnaire() {
super();
}
public Questionnaire(Integer id, String name, List<Question> questions) {
super();
this.id = id;
this.name = name;
this.questions = questions;
}
@Id
@GeneratedValue
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 String getAnswers() {
return answers;
}
public void setAnswers(String answers) {
this.answers = answers;
}
@OneToMany(mappedBy="questionnaire")
public List<Question> getQuestions() {
return questions;
}
public void setQuestions(List<Question> questions) {
this.questions = questions;
}
}
在试卷实体类中设置了一个List< Question >来保存试卷中的所有试题,设置上@OneToMany(mappedBy=”questionnaire”)表示以对方实体类中的关系属性为主导,也就是说被Question类中的questionnaire属性映射。
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
/*
* author
* 试题
* */
@Entity
@Table(name="t_question")
public class Question {
private Integer id;
private String name;
private Questionnaire questionnaire;
public Question() {
super();
}
public Question(Integer id, String name, Questionnaire questionnaire) {
super();
this.id = id;
this.name = name;
this.questionnaire = questionnaire;
}
@Id
@GeneratedValue
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;
}
@ManyToOne
@JoinColumn(name="questionnaireId")
public Questionnaire getQuestionnaire() {
return questionnaire;
}
public void setQuestionnaire(Questionnaire questionnaire) {
this.questionnaire = questionnaire;
}
}
属性questionnaire表示该试题属于的试卷,设置上@ManyToOne和@JoinColumn(name=”questionnaireId”),为数据库表中的外键起个新的名字叫做questionnaireId
在配置好hibernate配置文件后开始进行CRUD测试:
首先进行添加数据的测试,testCreate()
@Test
public void testCreate(){
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Questionnaire qn = new Questionnaire();
qn.setName("XXX公司3月转正考试");
Question q1 = new Question();
q1.setName("1、Java是一门OOP语言吗?A、是 B、不是");
q1.setQuestionnaire(qn);
Question q2 = new Question();
q2.setName("2、Java是哪个公司的作品?A、SUN B、MicroSoft");
q2.setQuestionnaire(qn);
session.saveOrUpdate(qn);
session.saveOrUpdate(q1);
session.saveOrUpdate(q2);
session.getTransaction().commit();
}
结果如下:
读取数据操作,testRead()
@Test
public void testRead(){
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Questionnaire qn = (Questionnaire) session.load(Questionnaire.class, 1);
List<Question> qList = qn.getQuestions();
System.out.println(qn.getName());
for(Question q : qList){
System.out.println(q.getName());
}
System.out.println("~~~~~~~~~~~~~~~~~");
Question q1 = (Question) session.load(Question.class, 1);
System.out.println(q1.getName()+"属于"+q1.getQuestionnaire().getName());
session.getTransaction().commit();
}
结果:
Hibernate:
select
questionna0_.id as id4_0_,
questionna0_.name as name4_0_,
questionna0_.answers as answers4_0_
from
t_questionnaire questionna0_
where
questionna0_.id=?
XXX公司3月转正考试
Hibernate:
select
questions0_.questionnaireId as question3_1_,
questions0_.id as id1_,
questions0_.id as id5_0_,
questions0_.name as name5_0_,
questions0_.questionnaireId as question3_5_0_
from
t_question questions0_
where
questions0_.questionnaireId=?
1、Java是一门OOP语言吗?A、是 B、不是
2、Java是哪个公司的作品?A、SUN B、MicroSoft
~~~~~~~~~~~~~~~~~
1、Java是一门OOP语言吗?A、是 B、不是属于XXX公司3月转正考试
修改操作,testUpdate()
@Test
public void testUpdate(){
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
//设置上答案
Questionnaire qn = (Questionnaire) session.load(Questionnaire.class, 1);
qn.setAnswers("A,A");
session.saveOrUpdate(qn);
session.getTransaction().commit();
}
结果如图:
最后测试删除数据操作,testDelete()
@Test
public void testDelete(){
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Question q = (Question) session.load(Question.class, 2);
session.delete(q);
session.getTransaction().commit();
}
结果:
下一篇介绍多对多映射,希望能对你有所帮助