Springboot获取rquest未使用@OneToMany获取第三级对象

时间:2019-04-03 08:01:41

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

我的数据库表设计如下。

通过这种结构,使用Springboot,我无法在TABLE-3之前获取TABLE-1的所有子元素

enter image description here

以下是相同的Entity类

表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
}

表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

enter image description here

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;

5 个答案:

答案 0 :(得分:1)

您缺少@JsonBackReference注释,这就是为什么您遇到stackoverflow错误的原因。@ JsonIgnore并非旨在解决Infinite Recursion问题,它只是忽略了带注释的属性被序列化或反序列化。

添加位置

    在SDKCollection.java中的
  1. 私有SDKMainCollection sdkcollectionobj; 回溯到SDKMaincollection,
  2. 在Ads.java中私有SDKCollection sdkcolsubobj 向后引用SDKCollection

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

答案 1 :(得分:0)

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

尝试fetch = FetchType.EAGER

答案 2 :(得分:0)

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

作为一种解决方法,也可以通过@Transaction注释控制器,以免出现延迟的初始化异常。 (fetch = FetchType.EAGER被认为是不正确的做法,请参见https://vladmihalcea.com/eager-fetching-is-a-code-smell/

更好的解决方案是将实体图用作获取计划,并且它与Spring DATA的集成非常好,请查看Spring Data JPA And NamedEntityGraphs

答案 3 :(得分:0)

可能有个情况。

  
      
  1. 在您有条件的情况下尝试使用UICollectionReusableView
  2.   
  3. 检查数据库中是否有数据(也是外键关系)。
  4.   

答案 4 :(得分:0)

所以最终我能够解决该错误。

由于我具有三级层次结构,所以这是我可以完成这项工作的唯一方法。

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

所以更改如下

表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

}

表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为层次结构创建了关系和额外的表。检索了最后一级的子表详细信息,而没有任何Stackoverflowerror。