已经有类似的帖子了。由于这已经较旧,我希望从那时起有所改变(FetchMode 如何在 Spring Data JPA 中工作)
如果关系用 EAGER 标记,我想一次性运行所有 jpa 存储库#findById。但是,spring 数据忽略了来自 hibernate 的 EAGER 规范和 FETCH.JOIN 注释。
是否有一个通用的解决方案,所有 findById 查询都在一个选择中执行?
我不想为每个查询编写单独的 JPL 或 EntityGraph。有人知道通用解决方案吗?
已经有类似的帖子了。由于这已经较旧,我希望从那时起有所改变(FetchMode 如何在 Spring Data JPA 中工作)
如果关系用 EAGER 标记,我想一次性运行所有 jpa 存储库#findById。但是,spring 数据忽略了来自 hibernate 的 EAGER 规范和 FETCH.JOIN 注释。
是否有一个通用的解决方案,所有 findById 查询都在一个选择中执行?
我不想为每个查询编写单独的 JPL 或 EntityGraph。有人知道通用解决方案吗?
最简单的选择是编写一个JpaRepository<T, Id>
. 这仍然是一个自定义存储库。但是,您不必编写这么多代码。您主要必须为每个相关类编写一个存储库接口,并findById(Long id)
用图形注释该方法。优点是,如果您编辑实体,存储库方法将不需要任何更改,因为您在实体类本身中定义了实体图。
@Entity
@NamedEntityGraph(name = "Department.detail",
attributeNodes = @NamedAttributeNode("employees"))
public class Department {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(fetch = FetchType.LAZY)
private List<Employee> employees;
// ...
}
public interface DepartmentRepository extends JpaRepository<Department, Long> {
@EntityGraph(value = "Department.detail", type = EntityGraphType.LOAD)
List<Department> findById(Long id);
}
由于 Spring 数据会忽略@Fetch(Fetchmode.JOIN)
注释或信息fetch = FetchType.EAGER
,因此您无法影响连接在实体本身中的方式。
另一种选择可以被认为是一种糟糕的软件工程风格:您可以在需要的地方直接调用数据库查询。这意味着您执行通常会在存储库中编写的代码。
public ClassWithQueryResults {
@PersistenceContext
private EntityManager entityManager;
public void methodWhereYouNeedYourResults() {
TypedQuery<Department> query = entityManager.createQuery(
"SELECT DISTINCT d FROM Department d LEFT JOIN d.employees e",
Department.class);
List<Department> departments = query.getResultList();
// ...
}
}
采用之前建议的想法,您可以创建一个对所有实体都有效的自定义存储库。第一步是在实体类中创建一个属性,在其中存储应该获取的属性。
public class Department extends AbstractEntity {
public static void String ATTRIBUTE_TO_FETCH = "employees";
...
}
通过一些调整,这可以扩展到应获取的所有字段的数组/列表。由于此属性直接存在于您的实体类中,因此出现任何错误和未来努力的可能性很低。显然,此属性在所有实体中都应具有相同的名称。
下一步是创建存储库。我提供了该findAll()
方法的示例。您只需将您想要拥有的实体的类名传递给它,其余的由泛型和反射完成。(考虑你想对异常做什么。)
public <T> List<T> findAll(Class<T> tClass)
throws NoSuchFieldException, IllegalAccessException {
String className = tClass.getSimpleName();
String attributeToFetch = (String)
tClass.getDeclaredField("ATTRIBUTE_TO_FETCH").get(null);
String queryString = String.format("SELECT DISTINCT p FROM %s p LEFT JOIN p.%s c",
className, attributeToFetch);
TypedQuery<T> query = entityManager.createQuery(queryString, tClass);
return query.getResultList();
}
根据您希望如何实现这一点,通过简单操作字符串来修改/生成查询可以提供 SQL 注入攻击的可能性。