加载OneToOne关系的嵌套对象

问题描述 投票:0回答:1

我有课

public class ToolSet {

...
    @OneToOne(fetch = FetchType.EAGER)
    private Contractor assignedTo;
...

}

public class Contractor {
...
    @ManyToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
    @JoinTable(
            name = "contractors_docs_photos",
            joinColumns = @JoinColumn(
                    name = "contractor_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(
                    name = "image_id", referencedColumnName = "id"))
    private Set<Image> idPhoto;

...
}

现在查询工具集时,我得到以下信息

 "toolset": [
      {
...
        "_embedded": {
          "assignedTo": {
            "firstName": "firstName",
          }
        }
      }

我也如何在承包商(照片)中加载嵌套对象?这样,当我加载工具集时,我会看到承包商,在concorcor内部,我会看到它的照片

spring-data spring-data-rest
1个回答
0
投票

正确的@ManyToMany关系

NO FetchType.EAGER

首先,我们应该看看您的@ManyToMany关系本身的实现。正如Vlad Mihalcea在this article中详细解释的那样,FetchType.EAGER不是一个好的选择。这导致许多不必要的数据库请求。

否CascadeType.REMOVE

此外,级联所有更改可能会导致严重的问题。删除特定对象可以自动级联以删除许多其他对象。由于described in this article(向下滚动一点),对于CascadeType.REMOVE关系应避免使用@ManyToManyCascadeType.ALL包括REMOVE。相反,您应该使用@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})

@ManyToMany关系的另一个示例可以在this Stackoverflow answer中找到。

初始化惰性关系

[懒关系(如提到的'好'@ManyToMany)不是由Hibernate(Spring Data自动使用的ORM)初始化的。在相应的变量中只能找到具有相关主键的代理。当有人尝试访问变量时,会自动从数据库中加载完整对象。这将导致其他数据库请求。

如果您已经事先知道需要对象(访问变量),则应在从数据库请求父对象时初始化关系(当从数据库请求ToolSet时,应加载其idPhoto以及。

在SQL中,这意味着这些不同表之间的联接。在JPA中,联接并不自动意味着已加载数据。因此,您应该使用访存联接或实体图来初始化惰性注释。 This article很好地概述了如何使用这些不同的初始化方式。

具有Criteria API的示例

在JPA中,有多种实现数据库请求的方式:JPQL作为查询语言和Criteria API(易于重构,不易出错)。因为我是Criteria API的爱好者,所以将向您展示一个示例,说明如何使用它初始化关系以及实体图的用法。

public Optional<ToolSet> findById(long id) {

    EntityGraph<ToolSet> graph = entityManager.createEntityGraph(ToolSet.class);
    graph.addAttributeNodes("assignedTo");

    Subgraph<Contractor> subgraph = graph.addSubgraph("assignedTo");
    subgraph.addAttributeNodes("idPhoto");

    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<ToolSet> cq = cb.createQuery(ToolSet.class);
    Root<ToolSet> root = cq.from(ToolSet.class);

    cq.where(cb.equal(root.get("id"), id));    // Assumption of id as PK
    TypedQuery<ToolSet> typedQuery = entityManager.createQuery(cq);
    typedQuery.setHint("javax.persistence.fetchgraph", graph);

    ToolSet response = null;
    try {
        response = typedQuery.getSingleResult();
    }
    catch(NoResultException nre) {}
    return Optional.ofNullable(response);
}

在此示例中,我假设您将ToolSet的主键称为id。要在编译时更好地查看错误,请查看hibernate-jpamodelgen。然后,您可以编写类似cq.where(cb.equal(root.get(ToolSet_.ID), id))的内容。

以上,我使用Optional。不必使用。无论如何,您可以重新研究使用它的优势。

© www.soinside.com 2019 - 2024. All rights reserved.