InheritanceType.JOINED,@ PrimaryKeyJoinColumn和嵌套的子类

时间:2014-08-05 18:17:41

标签: java hibernate jpa

我开始使用Hibernate有一个关于InheritanceType.JOINED和@PrimaryKeyJoinColumn的问题。

给出以下数据库表,其中员工引用人员和经理引用员工:

create table person (person_id int(10) auto_increment, 
                     name varchar(100),
                     primary key (person_id));

create table employee (employee_id int(10) auto_increment,
                       person_id int(10),
                       salary int(10),
                       primary key (employee_id));

create table manager (manager_id int(10) auto_increment,
                      employee_id int(10),
                      shares int(10),
                      primary key (manager_id));

我可以为Person和Employee创建前两个类,如下所示:

@Entity
@Table(name="person")
@Inheritance(strategy=InheritanceType.JOINED)
public class Person {

    @Id
    @GeneratedValue
    @Column(name="person_id")
    private int personId;

    @Column(name="name")
    private String name;
}


@Entity
@Table(name="employee")
@PrimaryKeyJoinColumn(name="person_id")
public class Employee extends Person {

    @GeneratedValue
    @Column(name="employee_id")
    private int employeeId;

    @Column(name="salary")
    private int salary;
}

对于Manager类,我不确定@PrimaryKeyJoinColumn使用哪个值。从阅读JPA规范我应该只在整个超类/子类/子类层次结构中使用一个id,我怀疑它应该是person_id。

我应该从manager表中删除employee_id列并将其替换为person_id吗?我问的原因是在数据库中使用“级联”主键似乎很自然(即管理器不直接引用人)但我相信Hibernate要求所有子类(不过“深”)包含一个外键返回超类。对我的断言的一些确认将非常有用。

2 个答案:

答案 0 :(得分:2)

您可以随意使用列名。 @PrimaryKeyJoinColumn注释用于告诉hibernate连接表中外键列的名称是什么。

@Entity
@Table(name = "manager")
@PrimaryKeyJoinColumn(name = "employee_id")
public class Manager extends Employee{
    private String branch;
}

此代码表示在manager表中有一个名为employee_id的列,它是employee表的外键。

这个注释是可选的,所以如果你不提供它,那么外键列的名称将与基类中的键名相同(超级基数,如果多级继承),在你的情况下如果你没有&#39 ; t提供然后任何子类将person_id作为外键。

如果您想在employee_id表格中将字段名称保留为manager,则必须提供此类内容。

@PrimaryKeyJoinColumn(name="employee_id")

如果您根本不提供此注释,则会有一个列名person_id用作employee表的外键。

这里有什么文件说明。

  

此批注指定用作的主键列   要加入另一个表的外键。

     

它用于连接实体子类的主表   JOINED映射策略到其超类的主表;它是   在SecondaryTable注释中用于将辅助表连接到a   主表;它可以用在OneToOne映射中   引用实体的主键用作外键   引用实体。

     

如果没有为子类指定PrimaryKeyJoinColumn批注   JOINED映射策略,假设外键列   与主表的主键列具有相同的名称   超类

修改

当我尝试通过id检索管理器时,Hibernate正在执行查询。

select
            manager0_.id as id1_4_0_,
            manager0_2_.name as name2_4_0_,
            manager0_1_.employee_id as employee1_1_0_,
            manager0_1_.salary as salary2_1_0_,
            manager0_.branch as branch1_2_0_ 
        from
            manager manager0_ 
        inner join
            employee manager0_1_ 
                on manager0_.id=manager0_1_.id 
        inner join
            person manager0_2_ 
                on manager0_.id=manager0_2_.id 
        where
            manager0_.id=?

正如您所见,经理有员工的外键,而不是人员表。我没有创建表。我使用了hbm2ddl=create

这意味着Hibernate本身使用级联主键创建表,而不是仅使用超级父键。

我理解你的困惑,即使我在休眠documentation中找不到任何东西。它只是说FK将指向超类主键。它没有指定直接超类或顶级超类。 虽然我检查了其他JPA实现,即OpenJPA。它确实特别指出FK指向直接超类。

答案 1 :(得分:2)

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@Table(name="Person")
public class Person implements Serializable{

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;

@Column(name="name")
private String name;

@Column(name="age")
private int age;

Person(String name,int age){
    this.name=name;
    this.age=age;

}

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}
}


@Entity
@Table(name="Student")
@PrimaryKeyJoinColumn(name="person_id")
public class Student extends Person{

@Column(name="stu_className")
private String className;

@Column(name="stu_collegeName")
private String collegeName;

Student(String name, int age, String className,String collegeName) {
    super(name, age);
    this.className=className;
    this.collegeName=collegeName;
}

public String getClassName() {
    return className;
}

public void setClassName(String className) {
    this.className = className;
}

public String getCollegeName() {
    return collegeName;
}

public void setCollegeName(String collegeName) {
    this.collegeName = collegeName;
}
}


@Entity
@Table(name="Teacher")
@PrimaryKeyJoinColumn(name="person_id")
public class Teacher extends Person{

@Column(name="qualification")
private String qualification;

@Column(name="designation")
private String designation;

Teacher(String name, int age,String qualification,String designation) {
    super(name, age);
    this.qualification=qualification;
    this.designation=designation;
}

public String getQualification() {
    return qualification;
}

public void setQualification(String qualification) {
    this.qualification = qualification;
}

public String getDesignation() {
    return designation;
}

public void setDesignation(String designation) {
    this.designation = designation;
}
}


import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;  
import org.hibernate.cfg.Configuration;

public enum HibernateUtil {

INSTANCE;
HibernateUtil(){
    buildSessionFactory();
}
private SessionFactory sessionFactory=null;

public SessionFactory getSessionFactory() {
    return sessionFactory;
}


public void setSessionFactory(SessionFactory sessionFactory) {
    this.sessionFactory = sessionFactory;
}


private  void buildSessionFactory() {
    Configuration configuration = new Configuration();

    configuration.addAnnotatedClass (Com.InheritenceType.Person.class);
    configuration.addAnnotatedClass (Com.InheritenceType.Teacher.class);
    configuration.addAnnotatedClass (Com.InheritenceType.Student.class);
    configuration.setProperty("connection.driver_class","com.mysql.jdbc.Driver");
    configuration.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/hibernate");                                
    configuration.setProperty("hibernate.connection.username", "root");     
    configuration.setProperty("hibernate.connection.password", "root");
    configuration.setProperty("dialect", "org.hibernate.dialect.MySQLDialect");
    configuration.setProperty("hibernate.hbm2ddl.auto", "update");
    configuration.setProperty("hibernate.show_sql", "true");
    configuration.setProperty(" hibernate.connection.pool_size", "10");
    configuration.setProperty(" hibernate.cache.use_second_level_cache", "true");
    configuration.setProperty(" hibernate.cache.use_query_cache", "true");
    configuration.setProperty(" cache.provider_class", "org.hibernate.cache.EhCacheProvider");
    configuration.setProperty("hibernate.cache.region.factory_class" ,"org.hibernate.cache.ehcache.EhCacheRegionFactory");

   // configuration
    StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
       sessionFactory = configuration.buildSessionFactory(builder.build());
       setSessionFactory(sessionFactory);
}


public  static SessionFactory getSessionFactoryInstance(){
    return INSTANCE.getSessionFactory();
}
} 


public class Main {

public static void main(String[] args) {
    HibernateUtil util=HibernateUtil.INSTANCE;
    SessionFactory factory=util.getSessionFactory();
    save(factory);
    retrieve(factory);
}

private static void retrieve(SessionFactory factory) {
    Session session=factory.openSession();

    Query query = session.createQuery("select s.id,s.name, s.age, s.qualification from Teacher s ");

    Iterator sal = query.iterate();
    System.out.println(" person_id \t name \t age \t qualification");
    while(sal.hasNext())
    {
    Object[] obj = (Object[]) sal.next();
    System.out.println(obj[0]+" \t "+ obj[1]+ " \t "+ obj[2]);

    }

}

private static void save(SessionFactory factory) {

    Session session=factory.openSession();
    Student student=new Student("Deepak", 30, "MCA", "Thapar");
    Teacher teacher=new Teacher("Bekaar Teachers", 60, "PHD", "Sr.professor");

    session.beginTransaction();

    session.save(student);
    session.save(teacher);

    session.getTransaction().commit();
    session.close();
}
}