Springboot получает запрос, не получая объект третьего уровня с @OneToMany - PullRequest
1 голос
/ 03 апреля 2019

У меня есть таблицы БД, сконструированные как показано ниже.

С этой структурой, используя Springboot, я не могу получить все дочерние элементы TABLE-1 до TABLE-3

enter image description here

Ниже приведены классы сущностей для того же

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
}

TABLE-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.

EDIT:

Эта проблема связана с тем, что оба OneToMany и ManyToOne находятся в одном и том же 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 ]

1 голос
/ 04 апреля 2019

вам не хватает аннотации @JsonBackReference, поэтому вы получаете ошибку переполнения стека. @ JsonIgnore не предназначен для решения проблемы бесконечной рекурсии, он просто игнорирует аннотированное свойство при сериализации или десериализации.

куда добавить

  1. в SDKCollection.java private SDKMainCollection sdkcollectionobj; обратная ссылка на SDKMaincollection,
  2. в Ads.java private SDKCollection sdkcolsubobj обратная ссылка на SDKCollection

выше, оба должны быть аннотированы @ JsonBackReference надеюсь, это поможет.

0 голосов
/ 08 апреля 2019

Итак, наконец, я смог устранить ошибку.

Поскольку у меня была трехуровневая иерархия, это был единственный способ сделать эту работу.

  • Удалено ManyToOne из дочерних табличных сущностей
  • Только хранится cascade = CascadeType.ALL,orphanRemoval = true в @OneToMany
  • Ни одна родительская таблица не была указана с @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
}

TABLE-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.

0 голосов
/ 03 апреля 2019

Ну, вы аннотируете поле объявлений с помощью @JsonIgnore, поэтому, когда оно сериализуется для отправки обратно HTTP-клиенту, Jackson Serializer игнорирует его, поэтому, если вы хотите включить поле объявлений, удалите @ JsonIgnore

Также в качестве обходного пути аннотируйте ваш контроллер с помощью @Transaction, чтобы вы не получали ленивое исключение при инициализации. (fetch = FetchType.EAGER считается плохой практикой, см. https://vladmihalcea.com/eager-fetching-is-a-code-smell/)

Лучшим решением является использование графа сущностей в качестве плана выборки, и он действительно хорошо интегрируется с Spring DATA, взгляните на Spring Data JPA и NamedEntityGraphs

0 голосов
/ 03 апреля 2019

могут быть случаи.

  1. в вашем состоянии попробуйте с fetch=FetchType.EAGER
  2. проверить, есть ли у вас данные в базе данных (также отношение внешнего ключа) или нет.
0 голосов
/ 03 апреля 2019
@JsonIgnore
@OneToMany(mappedBy = "sdkcolsubobj", cascade = CascadeType.ALL, fetch=FetchType.LAZY) 
private Set<Ads> ads

try fetch = FetchType.EAGER

...