继承映射(一)整个类继承树只一张表SINGLE_TABLE
根类一张表,将所有子类的属性都合并到根类中,此外还需要一个字段用于区分子类的类型。
company:
package com.persia.singletable; import java.io.Serializable; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.OrderBy; import javax.persistence.Table; @Entity @Table(name="company") public class Company implements Serializable { private Integer id; private String name; private Set<Employee> employees=new HashSet<Employee>(); @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; } @OneToMany(mappedBy="company",cascade=CascadeType.ALL,fetch=FetchType.EAGER) @OrderBy(value="id asc") public Set<Employee> getEmployees() { return employees; } public void setEmployees(Set<Employee> employees) { this.employees = employees; } public void addEmployee(Employee em){ if(!this.employees.contains(em)){ this.employees.add(em); em.setCompany(this); } } public void removeEmployee(Employee em){ em.setCompany(null); this.employees.remove(em); } }
Employee:
package com.persia.singletable; import java.io.Serializable; import javax.persistence.CascadeType; import javax.persistence.DiscriminatorColumn; import javax.persistence.DiscriminatorType; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.ManyToOne; import javax.persistence.Table; import javax.persistence.JoinColumn; @Entity @Table(name="employee") @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="Discriminator",discriminatorType=DiscriminatorType.STRING,length=30) public class Employee implements Serializable { private Integer id; private String name; private Company company; @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(cascade=CascadeType.PERSIST,optional=false) @JoinColumn(name="company_id") public Company getCompany() { return company; } public void setCompany(Company company) { this.company = company; } }
继承类:HourEmployee:
package com.persia.singletable; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.DiscriminatorValue; import javax.persistence.Entity; @Entity @DiscriminatorValue("rate") public class HourEmployee extends Employee { private Float rate; @Column(nullable=true) public Float getRate() { return rate; } public void setRate(Float rate) { this.rate = rate; } }
SalaryEmployee:
package com.persia.singletable; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.DiscriminatorValue; import javax.persistence.Entity; @Entity @DiscriminatorValue("salary") public class SalaryEmployee extends Employee { private Float salary; @Column(nullable=true) public Float getSalary() { return salary; } public void setSalary(Float salary) { this.salary = salary; } }
dao:
package com.persia.singletable; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.ejb.Remote; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; @Stateless @Remote({EmployeeDAO.class}) public class EmployeeDAOBean implements EmployeeDAO { @PersistenceContext private EntityManager em; @Override public void deleteCompany(Integer companyId) { Company c=em.find(Company.class, companyId); em.remove(c); } @Override public void deleteEmployee(Integer employeeId) { Employee e=em.find(Employee.class, employeeId); e.getCompany().getEmployees().remove(e); e.setCompany(null); em.remove(e); } @Override public List getAllCompany() { Query q=em.createQuery("from Company"); return q.getResultList(); } @Override public void insertCompany() { Company c=new Company(); c.setName("waltmart"); SalaryEmployee se=new SalaryEmployee(); se.setCompany(c); se.setName("salary-a"); se.setSalary(9999.0f); HourEmployee he=new HourEmployee(); he.setCompany(c); he.setName("hour-b"); he.setRate(888.0f); Set set=new HashSet(); set.add(se); set.add(he); c.setEmployees(set); em.persist(c); } @Override public void updateHourEmployee(Integer companyId, String name, float rate) { Company c=em.find(Company.class, companyId); Set set=c.getEmployees(); Iterator it=set.iterator(); while(it.hasNext()){ Employee e=(Employee)it.next(); if(e instanceof HourEmployee){ if(e.getName().equals(name)) ((HourEmployee)e).setRate(rate); } } } }
客户端:
package com.persia.singletabletest; import java.util.Iterator; import java.util.List; import java.util.Properties; import javax.naming.InitialContext; import javax.naming.NamingException; import com.persia.singletable.Company; import com.persia.singletable.Employee; import com.persia.singletable.EmployeeDAO; import com.persia.singletable.HourEmployee; import com.persia.singletable.SalaryEmployee; public class TestSingleTable { /** * @param args * @throws NamingException */ public static void main(String[] args) throws NamingException { Properties props=new Properties(); props.setProperty("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory"); props.setProperty("java.naming.provider.url","localhost:1099"); props.setProperty("java.naming.factory.url.pkgs","org.jboss.naming"); InitialContext context=new InitialContext(props); try{ EmployeeDAO edao=(EmployeeDAO)context.lookup("EmployeeDAOBean/remote"); edao.insertCompany(); // edao.deleteCompany(new Integer(1)); // edao.deleteEmployee(new Integer(1)); // edao.updateHourEmployee(new Integer(1), "hour-b", 95.0f); List ls=edao.getAllCompany(); if(ls!=null){ for(int i=0;i<ls.size();i++){ Company c=(Company)ls.get(i); if(c!=null){ System.out.println("=====公司:"+c.getName()+"====="); Iterator it=c.getEmployees().iterator(); while(it.hasNext()){ Employee e=(Employee)it.next(); if(e instanceof HourEmployee) System.out.println("临时工:"+((HourEmployee)e).getName()+" 薪水:"+((HourEmployee)e).getRate()); else System.out.println("正式员工:"+((SalaryEmployee)e).getName()+" 薪水:"+((SalaryEmployee)e).getSalary()); } } } } }catch(Exception e){ e.printStackTrace(); } } }
运行结果:
=====公司:waltmart===== 正式员工:salary-a 薪水:9999.0 临时工:hour-b 薪水:888.0
数据库:
mysql> desc company; +-------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(255) | YES | | NULL | | +-------+--------------+------+-----+---------+----------------+ 2 rows in set (0.03 sec) mysql> desc employee; +---------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------------+--------------+------+-----+---------+----------------+ | Discriminator | varchar(30) | NO | | NULL | | | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(255) | YES | | NULL | | | rate | float | YES | | NULL | | | salary | float | YES | | NULL | | | company_id | int(11) | NO | MUL | NULL | | +---------------+--------------+------+-----+---------+----------------+ 6 rows in set (0.02 sec) mysql> select * from company; +----+----------+ | id | name | +----+----------+ | 1 | waltmart | +----+----------+ 1 row in set (0.00 sec) mysql> select * from employee; +---------------+----+----------+------+--------+------------+ | Discriminator | id | name | rate | salary | company_id | +---------------+----+----------+------+--------+------------+ | rate | 1 | hour-b | 888 | NULL | 1 | | salary | 2 | salary-a | NULL | 9999 | 1 | +---------------+----+----------+------+--------+------------+ 2 rows in set (0.00 sec)
进行删除和修改:
修改
=====公司:waltmart===== 临时工:hour-b 薪水:95.0 正式员工:salary-a 薪水:9999.0
删除company后:
mysql> select * from employee; Empty set (0.00 sec) mysql> select * from company; Empty set (0.00 sec)
若删除SalaryEmployee:
=====公司:waltmart===== 临时工:hour-b 薪水:888.0
mysql> select * from employee; +---------------+----+--------+------+--------+------------+ | Discriminator | id | name | rate | salary | company_id | +---------------+----+--------+------+--------+------------+ | rate | 2 | hour-b | 888 | NULL | 1 | +---------------+----+--------+------+--------+------------+ 1 row in set (0.00 sec) mysql> select * from company; +----+----------+ | id | name | +----+----------+ | 1 | waltmart | +----+----------+ 1 row in set (0.00 sec)
------------------------------------------------------------------------------------------------------------------------------------------
SINGLE_TABLE的映射策略在所有继承策略中是最简单的,同时也是执行效率最高的,它仅仅需要对一个表进行管理和操作。在载入entity和多态连接时不需要进行任何关联,联合或子查询,因为所有的数据都存储在一个表中。
缺点是:
1.不能为所有子类的属性对应的字段定义not null 约束
2.在子类属性不是非常多的时候优先选择。(查询性能高)