One to many映射关系指的是两个实体间一个实体可以和多个实体有关联关系,但是多的这一端只能和一的这一端的一个实例有关系。它是一个1 到 n的关系。例如在任何的公司员工可以注册多个银行账户,一个银行账户只能和一个员工相关联,在这篇文章中我们将会学习怎么在Hibernate3中建立这种映射关系。
问题陈述
我们要写两个实体一个是Employee实体另一个是Account实体,这样多个银行账户就可以和一个员工关联了,但是这些账户不能被两个或以上的用户共享。
设计解决方案
这种问题可以使用两种方式解决。一种方式是在Account表中设置一个外键EMPLOYEE_ID,这一列指向Employee表的主键,这种方式没有两个账号可以和多个用户相关联,显然,为了完成这种限制,账号应该是独特的。另一种方式是建立一个连接表,比如说是叫EMPLOYEE_ACCOUNT,这个表有两列,EMP_ID作为EMPLOYEE表中主键的外键,对于ACCOUNT_ID也是这种情况。
使用外键连接
这种方式,两个实体都要负责建立关系并维护这种关系,EMPLOYEE实体应该申明的关系是one to many,Account实体应该声明的关系是many to one。首先来看一下关系设计:
EMPLOYEE实体
[java] view plain copy
- packagehibernate.test.oneToMany.foreignKeyAsso;
- importjava.io.Serializable;
- importjava.util.Set;
- importjavax.persistence.CascadeType;
- importjavax.persistence.Column;
- importjavax.persistence.Entity;
- importjavax.persistence.GeneratedValue;
- importjavax.persistence.GenerationType;
- importjavax.persistence.Id;
- importjavax.persistence.JoinColumn;
- importjavax.persistence.OneToMany;
- importjavax.persistence.Table;
- importjavax.persistence.UniqueConstraint;
- @Entity(name="ForeignKeyAssoEntity")
- @Table(name="Employee",uniqueConstraints={
- @UniqueConstraint(columnNames="ID"),
- @UniqueConstraint(columnNames="EMAIL")})
- publicclassEmployeeEntityimplementsSerializable{
- privatestaticfinallongserialVersionUID=-1798070786993154676L;
- @Id
- @GeneratedValue(strategy=GenerationType.IDENTITY)
- @Column(name="ID",unique=true,nullable=false)
- privateIntegeremployeeId;
- @Column(name="EMAIL",unique=true,nullable=false,length=100)
- privateStringemail;
- @Column(name="FIRST_NAME",unique=false,nullable=false,length=100)
- privateStringfirstName;
- @Column(name="LAST_NAME",unique=false,nullable=false,length=100)
- privateStringlastName;
- @OneToMany(cascade=CascadeType.ALL)
- @JoinColumn(name="EMPLOYEE_ID")
- privateSet<AccountEntity>accounts;
- publicIntegergetEmployeeId(){
- returnemployeeId;
- }
- publicvoidsetEmployeeId(IntegeremployeeId){
- this.employeeId=employeeId;
- }
- publicStringgetEmail(){
- returnemail;
- }
- publicvoidsetEmail(Stringemail){
- this.email=email;
- }
- publicStringgetFirstName(){
- returnfirstName;
- }
- publicvoidsetFirstName(StringfirstName){
- this.firstName=firstName;
- }
- publicStringgetLastName(){
- returnlastName;
- }
- publicvoidsetLastName(StringlastName){
- this.lastName=lastName;
- }
- publicSet<AccountEntity>getAccounts(){
- returnaccounts;
- }
- publicvoidsetAccounts(Set<AccountEntity>accounts){
- this.accounts=accounts;
- }
- }
Account实体
[java] view plain copy
- packagehibernate.test.oneToMany.foreignKeyAsso;
- importjava.io.Serializable;
- importjavax.persistence.Column;
- importjavax.persistence.Entity;
- importjavax.persistence.GeneratedValue;
- importjavax.persistence.GenerationType;
- importjavax.persistence.Id;
- importjavax.persistence.ManyToOne;
- importjavax.persistence.Table;
- importjavax.persistence.UniqueConstraint;
- @Entity(name="ForeignKeyAssoAccountEntity")
- @Table(name="ACCOUNT",uniqueConstraints={
- @UniqueConstraint(columnNames="ID")})
- publicclassAccountEntityimplementsSerializable
- {
- privatestaticfinallongserialVersionUID=-6790693372846798580L;
- @Id
- @GeneratedValue(strategy=GenerationType.IDENTITY)
- @Column(name="ID",unique=true,nullable=false)
- privateIntegeraccountId;
- @Column(name="ACC_NUMBER",unique=true,nullable=false,length=100)
- privateStringaccountNumber;
- @ManyToOne
- privateEmployeeEntityemployee;
- publicIntegergetAccountId(){
- returnaccountId;
- }
- publicvoidsetAccountId(IntegeraccountId){
- this.accountId=accountId;
- }
- publicStringgetAccountNumber(){
- returnaccountNumber;
- }
- publicvoidsetAccountNumber(StringaccountNumber){
- this.accountNumber=accountNumber;
- }
- publicEmployeeEntitygetEmployee(){
- returnemployee;
- }
- publicvoidsetEmployee(EmployeeEntityemployee){
- this.employee=employee;
- }
- }
测试代码
[java] view plain copy
- packagehibernate.test.oneToMany;
- importhibernate.test.HibernateUtil;
- importhibernate.test.oneToMany.foreignKeyAsso.AccountEntity;
- importhibernate.test.oneToMany.foreignKeyAsso.EmployeeEntity;
- importjava.util.HashSet;
- importjava.util.Set;
- importorg.hibernate.Session;
- publicclassTestForeignKeyAssociation
- {
- publicstaticvoidmain(String[]args)
- {
- Sessionsession=HibernateUtil.getSessionFactory().openSession();
- session.beginTransaction();
- AccountEntityaccount1=newAccountEntity();
- account1.setAccountNumber("Accountdetail1");
- AccountEntityaccount2=newAccountEntity();
- account2.setAccountNumber("Accountdetail2");
- AccountEntityaccount3=newAccountEntity();
- account3.setAccountNumber("Accountdetail3");
- //AddnewEmployeeobject
- EmployeeEntityfirstEmployee=newEmployeeEntity();
- firstEmployee.setEmail("demo-user-first@mail.com");
- firstEmployee.setFirstName("demo-one");
- firstEmployee.setLastName("user-one");
- EmployeeEntitysecondEmployee=newEmployeeEntity();
- secondEmployee.setEmail("demo-user-second@mail.com");
- secondEmployee.setFirstName("demo-two");
- secondEmployee.setLastName("user-two");
- Set<AccountEntity>accountsOfFirstEmployee=newHashSet<AccountEntity>();
- accountsOfFirstEmployee.add(account1);
- accountsOfFirstEmployee.add(account2);
- Set<AccountEntity>accountsOfSecondEmployee=newHashSet<AccountEntity>();
- accountsOfSecondEmployee.add(account3);
- firstEmployee.setAccounts(accountsOfFirstEmployee);
- secondEmployee.setAccounts(accountsOfSecondEmployee);
- //SaveEmployee
- session.save(firstEmployee);
- session.save(secondEmployee);
- session.getTransaction().commit();
- HibernateUtil.shutdown();
- }
- }
- Output:
- Hibernate:insertintoEmployee(EMAIL,FIRST_NAME,LAST_NAME)values(?,?,?)
- Hibernate:insertintoACCOUNT(ACC_NUMBER,employee_ID)values(?,?)
- Hibernate:insertintoACCOUNT(ACC_NUMBER,employee_ID)values(?,?)
- Hibernate:insertintoEmployee(EMAIL,FIRST_NAME,LAST_NAME)values(?,?,?)
- Hibernate:insertintoACCOUNT(ACC_NUMBER,employee_ID)values(?,?)
- Hibernate:updateACCOUNTsetEMPLOYEE_ID=?whereID=?
- Hibernate:updateACCOUNTsetEMPLOYEE_ID=?whereID=?
- Hibernate:updateACCOUNTsetEMPLOYEE_ID=?whereID=?
使用关联表
这种方式使用关联表存储两个实体间的关系@JoinTable注解是用来建立这种关系的,先来看一下数据库模式
EMPLOYEE实体
[java] view plain copy
- packagehibernate.test.oneToMany.joinTable;
- importjava.io.Serializable;
- importjava.util.Set;
- importjavax.persistence.CascadeType;
- importjavax.persistence.Column;
- importjavax.persistence.Entity;
- importjavax.persistence.GeneratedValue;
- importjavax.persistence.GenerationType;
- importjavax.persistence.Id;
- importjavax.persistence.JoinColumn;
- importjavax.persistence.JoinTable;
- importjavax.persistence.OneToMany;
- importjavax.persistence.Table;
- importjavax.persistence.UniqueConstraint;
- @Entity(name="JoinTableEmployeeEntity")
- @Table(name="Employee",uniqueConstraints={
- @UniqueConstraint(columnNames="ID"),
- @UniqueConstraint(columnNames="EMAIL")})
- publicclassEmployeeEntityimplementsSerializable
- {
- privatestaticfinallongserialVersionUID=-1798070786993154676L;
- @Id
- @GeneratedValue(strategy=GenerationType.IDENTITY)
- @Column(name="ID",unique=true,nullable=false)
- privateIntegeremployeeId;
- @Column(name="EMAIL",unique=true,nullable=false,length=100)
- privateStringemail;
- @Column(name="FIRST_NAME",unique=false,nullable=false,length=100)
- privateStringfirstName;
- @Column(name="LAST_NAME",unique=false,nullable=false,length=100)
- privateStringlastName;
- @OneToMany(cascade=CascadeType.ALL)
- @JoinTable(name="EMPLOYEE_ACCOUNT",joinColumns={@JoinColumn(name="EMPLOYEE_ID",referencedColumnName="ID")}
- ,inverseJoinColumns={@JoinColumn(name="ACCOUNT_ID",referencedColumnName="ID")})
- privateSet<AccountEntity>accounts;
- publicIntegergetEmployeeId(){
- returnemployeeId;
- }
- publicvoidsetEmployeeId(IntegeremployeeId){
- this.employeeId=employeeId;
- }
- publicStringgetEmail(){
- returnemail;
- }
- publicvoidsetEmail(Stringemail){
- this.email=email;
- }
- publicStringgetFirstName(){
- returnfirstName;
- }
- publicvoidsetFirstName(StringfirstName){
- this.firstName=firstName;
- }
- publicStringgetLastName(){
- returnlastName;
- }
- publicvoidsetLastName(StringlastName){
- this.lastName=lastName;
- }
- publicSet<AccountEntity>getAccounts(){
- returnaccounts;
- }
- publicvoidsetAccounts(Set<AccountEntity>accounts){
- this.accounts=accounts;
- }
- }
Account实体
[java] view plain copy
- packagehibernate.test.oneToMany.joinTable;
- importjava.io.Serializable;
- importjavax.persistence.Column;
- importjavax.persistence.Entity;
- importjavax.persistence.GeneratedValue;
- importjavax.persistence.GenerationType;
- importjavax.persistence.Id;
- importjavax.persistence.Table;
- importjavax.persistence.UniqueConstraint;
- @Entity(name="JoinTableAccountEntity")
- @Table(name="ACCOUNT",uniqueConstraints={
- @UniqueConstraint(columnNames="ID")})
- publicclassAccountEntityimplementsSerializable
- {
- privatestaticfinallongserialVersionUID=-6790693372846798580L;
- @Id
- @GeneratedValue(strategy=GenerationType.IDENTITY)
- @Column(name="ID",unique=true,nullable=false)
- privateIntegeraccountId;
- @Column(name="ACC_NUMBER",unique=true,nullable=false,length=100)
- privateStringaccountNumber;
- publicIntegergetAccountId(){
- returnaccountId;
- }
- publicvoidsetAccountId(IntegeraccountId){
- this.accountId=accountId;
- }
- publicStringgetAccountNumber(){
- returnaccountNumber;
- }
- publicvoidsetAccountNumber(StringaccountNumber){
- this.accountNumber=accountNumber;
- }
- }
在配置文件中配置实体,我们已经有了两个在运行时的实体,我们必须在配置文件中增加他们。请注意只有一个集合实体可以在配置文件中配置,否则会有意外的情况发生
[java] view plain copy
- <?xmlversion="1.0"encoding="utf-8"?>
- <!DOCTYPEhibernate-configurationPUBLIC
- "-//Hibernate/HibernateConfigurationDTD3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
- <hibernate-configuration>
- <session-factory>
- <propertyname="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
- <propertyname="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernatetest</property>
- <propertyname="hibernate.connection.password">XXXXXX</property>
- <propertyname="hibernate.connection.username">root</property>
- <propertyname="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
- <propertyname="show_sql">true</property>
- <propertyname="hbm2ddl.auto">create</property>
- <mappingclas="hibernate.test.oneToMany.foreignKeyAsso.AccountEntity"></mapping>
- <mappingclas="hibernate.test.oneToMany.foreignKeyAsso.EmployeeEntity"></mapping>
- </session-factory>
- </hibernate-configuration>
测试代码:
[java] view plain copy
- packagehibernate.test.oneToMany;
- importhibernate.test.HibernateUtil;
- importhibernate.test.oneToMany.joinTable.AccountEntity;
- importhibernate.test.oneToMany.joinTable.EmployeeEntity;
- importjava.util.HashSet;
- importjava.util.Set;
- importorg.hibernate.Session;
- publicclassTestJoinTable
- {
- publicstaticvoidmain(String[]args)
- {
- Sessionsession=HibernateUtil.getSessionFactory().openSession();
- session.beginTransaction();
- AccountEntityaccount1=newAccountEntity();
- account1.setAccountNumber("123-345-65454");
- AccountEntityaccount2=newAccountEntity();
- account2.setAccountNumber("123-345-6542222");
- //AddnewEmployeeobject
- EmployeeEntityemp=newEmployeeEntity();
- emp.setEmail("demo-user@mail.com");
- emp.setFirstName("demo");
- emp.setLastName("user");
- Set<AccountEntity>accounts=newHashSet<AccountEntity>();
- accounts.add(account1);
- accounts.add(account2);
- emp.setAccounts(accounts);
- //SaveEmployee
- session.save(emp);