spring 添加@ManyToOne是否会导致对引用表进行额外查询?

e3bfsja2  于 2023-09-29  发布在  Spring
关注(0)|答案(2)|浏览(116)

如果我使用带有获取类型LAZY或任何其他jpaMap注解的@ManyToOne,jpa会在Map的实体上运行查询来获取id吗?
比如

@Entity
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @OneToMany(mappedBy = "department", cascade = CascadeType.ALL)
    private List<Employee> employees = new ArrayList<>();

    // Constructors, getters, setters, and other properties
}

员工:

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @ManyToOne
    @JoinColumn(name = "department_id", fetch= FetchType.LAZY)
    private Department department;

    // Constructors, getters, setters, and other properties
}

现在,假设我尝试在Employee上查找by,并尝试从与该雇员对应的部门获取id,Hibernate是否会向Department类发布一个额外的查询,并从employee = 'x'的部门获取id。或者部门id将与employee实体存储在一起,我可以在不增加查询时间的情况下获取它?因为部门ID存在于mysql中的employee表中。

Employee emp = employeeRepository.findByName("John");
String deparmentId = emp.getDeparment().getId(); //Extra query time or not? As Id is stored in the mysql table
emp.getDepartment().getName(); //Does causes extra query
eyh26e7m

eyh26e7m1#

当您使用Spring JPA进行查询时,您将获得表示返回查询值的数据对象的示例。这 * 包括关系数据 *,只要你有适当的注解(你这样做)。
JPA正在将数据库表Map到Entity的示例。在从查询(findBy等)中检索实体示例后,任何字段(通过getter/setter)都可以立即访问。
比如说。如果您像这样查询单个部门:

Optional<Department> aDepartmentOpt = departmentRepository.findById(2);

// assume we checked aDepartmentOpt for isEmpty()
Department department = aDepartmentOpt.get();

// lets get its employees
List<Employee> dptEmployees = department.getEmployees();

// do stuff with it... we have access to its data already
for(Employee e : dptEmployees) {
    System.out.println("Employee " + e.getId() + " - " + e.getName());
}

反之亦然:

Optional<Employee> employeeOpt = employeeRepository.findById(2);

// assume we checked employeeOpt for isEmpty()
Employee employee = employeeOpt.get();

// lets get the employees department
Department department = employee.getDepartment();

// do stuff with it... we dont need to query the department cause we have its data right here:
System.out.println("Department " + department.getId() + " - " + department.getName());

请注意,当您使用mappedBy时,您将为Spring JPA提供字段名称,以便它可以在查询时将其与数据对象的示例相关联。
希望这对你有帮助。

7cwmlq89

7cwmlq892#

是的,调用getDepartment()将强制对惰性关系的数据库进行提取。如果getDepartment()调用立即从数据库中获取,或者如果您获得一个代理对象,调用任何内容然后从数据库中获取,这是特定于实现(和配置)的,所以我不会依赖它。如果您希望在只获取Employee示例而不知道部门是否已被获取时访问FK值(“department_id”),请将其直接Map为实体中的基本Long属性。你可以有多个Map到同一个“department_id”,只要你只指定一个为可写的(所以所有其他的为updatable=false,insertable=false)。Ie

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @Column(name = "department_id", insertable=false, updatable=false)
    private Long departmentId;

    @ManyToOne
    @JoinColumn(name = "department_id", fetch= FetchType.LAZY)
    private Department department;

    // Constructors, getters, setters, and other properties
}

这允许您继续在查询中使用和引用department来执行联接,但也允许您直接使用departmentId来避免它们。即:

"select employee from Employee employee where employee.department.id =:deptId"

vs

"select employee from Employee employee where employee.departmentId = :deptId"

第一个查询应该强制对部门进行内部联接,而第二个查询则没有。
根据您的应用程序需求,您还可以反转设置“department_id”列值的属性,以便可以通过departmentId设置它-这在您可能希望通过REST合并员工而不必构建回Department对象并处理阅读和合并它们时可能很有用-序列化只需要departmentId long。

相关问题