【问题标题】:Springboot get rquest not fetching third level object with @OneToManySpring Boot 获取请求未使用 @OneToMany 获取第三级对象
【发布时间】:2019-08-24 16:15:01
【问题描述】:

我的数据库表设计如下。

使用这种结构,使用 Springboot,我无法获取 TABLE-1 直到 TABLE-3 的所有子元素

以下是相同的实体类

TABLE-1 (SDKMainCollection.java)

@Entity
@Table(name="sdkmaincollection")
public class SDKMainCollection {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String sdkgroupname;
    @JsonIgnore
    @OneToMany(mappedBy = "sdkcollectionobj", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Set<SDKCollection> sdkcollection;

    public SDKMainCollection() {
    }

    public SDKMainCollection(int id,String sdkGroupName) {
        this.id= id;
        this.sdkgroupname =sdkGroupName;
    }

    public SDKMainCollection(String sdkGroupName) {
        this.sdkgroupname =sdkGroupName;
    }
    //Getters and Setters
}

表 2 (SDKCollection.java)

@Entity
@Table(name="sdkcollection")
public class SDKCollection {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String sdktitle;
    private String sdkid;
    private String sdkresourceid;
    private String sdkdescription;
    private String sdkimageName;
    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "sdkmaincollection_id")
    private SDKMainCollection sdkcollectionobj;
    @JsonIgnore
    @OneToMany(mappedBy = "sdkcolsubobj", cascade = CascadeType.ALL, fetch=FetchType.LAZY) 
    private Set<Ads> ads;

    public SDKCollection() {
    }
    public SDKCollection(int id, String sdkTitle, String sdkId, String sdkresourceId, String sdkdescription,
            String sdkimageName,SDKMainCollection sdkObj) {
        this.id = id;
        this.sdktitle = sdkTitle;
        this.sdkid = sdkId;
        this.sdkresourceid = sdkresourceId;
        this.sdkdescription = sdkdescription;
        this.sdkimageName = sdkimageName;
        this.sdkcollectionobj = sdkObj;
    }
    public SDKCollection(String sdkTitle, String sdkId, String sdkresourceId, String sdkdescription,
            String sdkimageName,SDKMainCollection sdkObj) {

        this.sdktitle = sdkTitle;
        this.sdkid = sdkId;
        this.sdkresourceid = sdkresourceId;
        this.sdkdescription = sdkdescription;
        this.sdkimageName = sdkimageName;
        this.sdkcollectionobj = sdkObj;
    }
    //Getters and Setters
}

TABLE-3 (Ads.java)

@Entity
@Table(name="ads")
public class Ads {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String adtitle;
    private String adtag;
    private String adtype;
    private String imagename;
    private String controlid;
    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "sdkcollection_id")
    private SDKCollection sdkcolsubobj;

    public Ads() {

    }
    public Ads(int id, String adTitle, String adTag, String adType, String imageName, String controlID,
            SDKCollection sdkcollection     
            ) {
        this.id = id;
        this.adtitle = adTitle;
        this.adtag = adTag;
        this.adtype = adType;
        this.imagename = imageName;
        this.controlid = controlID;
        this.sdkcolsubobj = sdkcollection;
    }
    public Ads(String adTitle, String adTag, String adType, String imageName, String controlID
            ,SDKCollection sdkcollection) {
        this.adtitle = adTitle;
        this.adtag = adTag;
        this.adtype = adType;
        this.imagename = imageName;
        this.controlid = controlID;
        this.sdkcolsubobj = sdkcollection;
    }
    //Getters and Setters
}

下面是我用于获取元素的控制器类

@RestController
@RequestMapping("/api/sdk/")
@CrossOrigin
public class GetSDKController {
    @Autowired
    private SDKMainCollectionRepo sdkMainCollectionRepo;
    @Autowired
    private SDKCollectionRepo sdkCollectionRepo;
    @Autowired
    private AdsRepo adsRepo;
    @GetMapping("/getAllSDKs")
    public List<SDKMainCollection> getAllSDK(){
        sdkDataMapper = new SDKDataMapper(sdkMainCollectionRepo,sdkCollectionRepo,adsRepo);
        List<SDKMainCollection> totalResp  = (List<SDKMainCollection>) sdkMainCollectionRepo.findAll();
        System.out.println("getAllSDK = totalResp "+totalResp);

        //NOT GETTING WHAT IS EXPECTED

        return totalResp;
    }
}

以下是我的期望,但我得到了Stackoverflow error

Stackoverflow 错误日志:

java.lang.StackOverflowError: null
    at java.util.AbstractCollection.toString(Unknown Source) ~[na:1.8.0_131]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:328) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at com.dvservices.models.SDKMainCollection.toString(SDKMainCollection.java:59) ~[classes/:na]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at com.dvservices.models.SDKCollection.toString(SDKCollection.java:118) ~[classes/:na]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at java.util.AbstractCollection.toString(Unknown Source) ~[na:1.8.0_131]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:328) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at com.dvservices.models.SDKMainCollection.toString(SDKMainCollection.java:59) ~[classes/:na]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at com.dvservices.models.SDKCollection.toString(SDKCollection.java:118) ~[classes/:na]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at java.util.AbstractCollection.toString(Unknown Source) ~[na:1.8.0_131]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:328) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at com.dvservices.models.SDKMainCollection.toString(SDKMainCollection.java:59) ~[classes/:na]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at com.dvservices.models.SDKCollection.toString(SDKCollection.java:118) ~[classes/:na]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at java.util.AbstractCollection.toString(Unknown Source) ~[na:1.8.0_131]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:328) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]

我猜问题可能在于获取最后一个数组并导致 Stackoverflow 错误。

编辑:

这个问题是因为OneToManyManyToOne 在同一个SDKCollection 类中,因为它位于层次结构的中间?

public class SDKCollection {

       ........
       @JsonIgnore
       @ManyToOne(fetch = FetchType.LAZY)
       @JoinColumn(name = "sdkmaincollection_id")
       private SDKMainCollection sdkcollectionobj;

       @JsonIgnore
       @OneToMany(mappedBy = "sdkcolsubobj", cascade = CascadeType.ALL, fetch=FetchType.LAZY) 
       private Set<Ads> ads;

【问题讨论】:

    标签: java spring-boot spring-data-jpa entity spring-restcontroller


    【解决方案1】:

    您缺少 @JsonBackReference 注释,这就是您收到 stackoverflow 错误的原因。@JsonIgnore 并非旨在解决无限递归问题,它只是忽略了被序列化或反序列化的注释属性。

    在哪里添加

    1. 在 SDKCollection.java 中 私有 SDKMainCollection sdkcollectionobj; 反向引用 SDKMaincollection,
    2. 在 Ads.java 中 private SDKCollection sdkcolsubobj 反向引用 SDKCollection

    以上两者都应使用 @JsonBackReference 进行注释 希望有帮助。

    【讨论】:

      【解决方案2】:
      @JsonIgnore
      @OneToMany(mappedBy = "sdkcolsubobj", cascade = CascadeType.ALL, fetch=FetchType.LAZY) 
      private Set<Ads> ads
      

      尝试 fetch=FetchType.EAGER

      【讨论】:

      • 很抱歉错过了沟通,我在 EAGER 和 LAZY 中都遇到了 Stackoverflow 错误。它不取回任何数据
      【解决方案3】:

      好吧,您正在使用 @JsonIgnore 注释 ads 字段,因此当它被序列化以发送回 HTTP 客户端时,Jackson 序列化程序会忽略它,因此如果您想包含 ads 字段,请删除 @JsonIgnore

      还可以通过@Transaction 注释您的控制器,这样您就不会遇到延迟初始化异常。 (fetch=FetchType.EAGER 被认为是一种不好的做法,请参阅https://vladmihalcea.com/eager-fetching-is-a-code-smell/

      更好的解决方案是使用实体图作为抓取计划,它与 Spring DATA 集成得非常好,看看Spring Data JPA And NamedEntityGraphs

      【讨论】:

      • 很抱歉错过了沟通,我在 EAGER 和 LAZY 中都遇到了 Stackoverflow 错误。它不取回任何数据
      • 好的没问题!好吧,您的控制器中有 System.out.println("getAllSDK = totalResp "+totalResp);所以toString() 的totalResp 被调用,它调用列表中的每个SDKMainCollection,SDKMainCollection 的toString() 也调用它的每个字段的toString() ......并且父母toString() 被回调......所以无限toString() 方法调用的数量.. 这里讨论stackoverflow.com/questions/3593893/…
      【解决方案4】:

      所以我终于能够解决这个错误了。

      由于我有三层结构,这是我完成这项工作的唯一方法。

      • 从子表实体中删除了 ManyToOne
      • 仅在@OneToMany 中保留cascade = CascadeType.ALL,orphanRemoval = true
      • 没有使用子表中的@ManyToOne 引用父表

      所以变化如下

      TABLE-1 (SDKMainCollection.java)

      @Entity
      @Table(name="sdkmaincollection")
      public class SDKMainCollection {
      
      ...
      ...
      @OneToMany(cascade = CascadeType.ALL,orphanRemoval = true)
      private List<Sdkcollection> sdkCollection = new ArrayList<Sdkcollection>();
      
      //No Constructor required
      //Kept only getters and setters
      }
      

      表 2 (SDKCollection.java)

      @Entity
      @Table(name="sdkcollection")
      public class SDKCollection {
      
      ...
      ...
      @OneToMany(cascade = CascadeType.ALL,orphanRemoval = true)
      private List<Ads> ads = new ArrayList<Ads>();
      
      //No parent table with @ManyToOne was refered
      //No Constructor required
      //Kept only getters and setters
      
      }
      

      TABLE-3 (Ads.java)

      @Entity
      @Table(name="ads")
      public class Ads {
      
      
      ...
      ...
      //No parent table with @ManyToOne was refered
      //No Constructor required
      //Kept only getters and setters
      
      }
      

      Hibernate 为层次结构创建了关系和额外的表。在没有任何 Stackoverflow 错误的情况下检索了最后一级的子表详细信息。

      【讨论】:

        【解决方案5】:

        可能有一个案例。

        1. 在你的条件下尝试fetch=FetchType.EAGER
        2. 检查数据库中是否有数据(还有外键关系)。

        【讨论】:

        • 很抱歉错过了沟通,我在 EAGER 和 LAZY 中都遇到了 Stackoverflow 错误。它不取回任何数据
        • 我检查了我的数据库,它的 FK 关系设置正确
        • 这可能是由于 toString() 方法。请检查它可能是重复的类属性。
        猜你喜欢
        • 2020-12-09
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-06
        • 2020-05-23
        • 2018-09-24
        • 1970-01-01
        相关资源
        最近更新 更多