@ManyToOne在插入新记录时获取连接表的所有列

时间:2017-02-05 09:23:59

标签: hibernate jpa

我正在使用JPA 2.0与EclipseLink持久性提供程序和Hibernate实体管理器4.3.10.Final。我在Employee和Office实体之间有@ManyToOne关系。我正在使用EntityManagerFactory插入一个新的Employee。员工实例引用现有的Office。代码有效但查询显示它正在获取Office的所有列而不仅仅是officeId。如何微调查询以避免在插入新员工时获取Office的所有列?我尝试在@ManyToOne上使用FetchType.LAZY,但它不起作用。

Employee.java

@Entity  
public class Employee { 

    @Id
    @SequenceGenerator(name="employeeSequence",allocationSize=1, sequenceName="EMP_SEQ")    
    @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="employeeSequence")
    private int empId;  

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

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

    @Column(name="DOB")
    private Date dateOfBirth;

    private Date hireDate;

    @ManyToOne
    @JoinColumn(name="location") 
    private int location;   

Office.java

@Entity
public class Office { 
    @Id
    private int officeId;

    private String location;
    private String address1;
    private String address2;
    private String city;
    private String state;
    private String country;
    private String zipcode;

创建Employee对象的代码

Employee emp = new Employee();
emp.setFirstName(firstName);        
emp.setLastName(lastName);
emp.setDateOfBirth(dob);
emp.setHireDate(hiredate);

Office office = new Office();
office.setOfficeId(officeId);
emp.setLocation(office);

SQL查询

Hibernate: 
select
     EMP_SEQ.nextval 
 from
    dual

Hibernate: 
select
     office_.officeId,
    office_.address1 as address2_1_,
    office_.address2 as address3_1_,
    office_.city as city4_1_,
    office_.country as country5_1_,
    office_.location as location6_1_,
    office_.state as state7_1_,
    office_.zipcode as zipcode8_1_ 
from
   Office office_ 
 where
   office_.officeId=?

Hibernate: 
insert 
 into
   Emp
     (DOB, FIRST_NAME, hireDate, LAST_NAME, location, empId) 
 values (?, ?, ?, ?, ?, ?)

1 个答案:

答案 0 :(得分:0)

开发人员在保存新对象时,基于某些外键值查询数据库以获取关系的持久实例是很常见的,如下所示:

@Entity
public class Employee {
  // other stuff removed for breavity
  @ManyToOne
  private Office office;
}

@Entity
public class Office {
  // no relationship back to Employee
}

// some repository method
public Employee save(String employeeName, Long officeId) {
  final Office office = entityManager.find( Office.class, offceId );
  final Employee employee = new Employee( employeeName, officeId );
  entityManager.persist( employee );
  return employee;
}

在这种情况下,持久性提供程序将查询数据库以构造Office实体,以便在持久化时将标识符与Employee相关联。正如您所注意到的,这不仅是不必要的,而且会影响性​​能。

避免数据库提取的另一个解决方案是在本机Hibernate API方面使用Session#load或在JPA方面使用EntityManager#getReference。对于所有意图和目的,它们是同义词,因为它们接受类类型和主键值,并构造代表类型类型的代理,如果访问它的内部状态将被懒惰地加载。

所以通过将上面的存储库方法更改为:

// some repository method
public Employee save(String employeeName, Long officeId) {
  final Office office = entityManager.getReference( Office.class, offceId );
  final Employee employee = new Employee( employeeName, officeId );
  entityManager.persist( employee );
  return employee;
}

不应再对Office的数据存储进行提取。