Как сохранить коллекцию объектов при помощи JPA?

Доброго времени суток всем! Проблема моя такова: с клиента приходит JSON :
{"name":"Строительство","subCategories":[{"name":"электроинструменты"},{"name":"грузовые машины"}]}


Т.е тут я передаю имя Высшей категории, и массив подкатегорий с параметрами. Необходимо сохранить в БД подкатегории. Вот собственно сущности:

HighCategory.java:

@Entity
@Table(name = "high_category")
public class HighCategory extends BaseModel {


    @Column(name = "NAME")
    @NotEmpty
    private String name;

    @JsonIgnore
    @OneToMany(mappedBy = "highCategory",fetch = FetchType.LAZY,cascade = CascadeType.ALL)
    private List<SubCategory> subCategories;

    public HighCategory(){}
    public HighCategory(HighCategoryDeserialize highCategoryDeserialize){
        this.name=highCategoryDeserialize.getName();
        this.subCategories=highCategoryDeserialize.getSubCategories();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<SubCategory> getSubCategories() {
        return subCategories;
    }

    public void setSubCategories(List<SubCategory> subCategories) {
        this.subCategories = subCategories;
    }


SubCategory.java:

@Entity
@Table(name = "middle_category")
public class SubCategory extends BaseModel {


    @Column(name = "NAME")
    private String name;


    @ManyToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name = "HIGH_CATEGORY_ID")
    private HighCategory highCategory;  

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public HighCategory getHighCategory() {
        return highCategory;
    }

    public void setHighCategory(HighCategory highCategory) {
        this.highCategory = highCategory;
    }


Пока что я придумал 2 пути решить эту проблему, но они настолько неказисты, что я думаю, есть решения более адекватные:

1-ое решение:

@RequestMapping(value = "/addMiddleCategory", method = RequestMethod.POST, produces = "text/plain;charset=UTF-8")
    public String addHighCategory(@RequestBody HighCategoryDeserialize highCategoryDeserialize, BindingResult bindingResult) {
        String resultOfOperation;
        List<SubCategory> subCategoryList=highCategoryDeserialize.getSubCategories();
        HighCategory highcategory=new HighCategory(highCategoryDeserialize);
        for(SubCategory subCategory:subCategoryList){
            subCategory.setHighCategory(highcategory);
        }
        return subCategoryService.addSubCategory(subCategoryList);
    }


highCategoryDeserialize -переменная класса HighCategoryDeserialize, который абсолютно идентичен HighCategory. Сделано это для того, чтобы Jackson смог десериализовать и List, который в HighCateogry стоит как @JsonIngnore, чтобы при Get запросе не вытягивать доп информацию. Т.е тут я фактически копирую HighCategoryDeserialize в HighCategory, т.к HighCategory запамлен и с ним может Hibernate работать. Потом я сетаю всем подкатегориям этот HighCategory. Ну а в DAO слое уже делаю :
@Override
    public String addSubCategory(List<SubCategory> subCategories) {
        String resultOfOperation;

        for (SubCategory subCategory : subCategories) {
            System.out.println(subCategory);
            entityManager.persist(subCategory);
        }

        return resultOfOperation="Operation complete!";
    }


Но подход такой, создает одинаковую Высшую категорию, что мне вообще не с руки + по-моему у Hibernat-а есть какой-нибудь более адекватное решение.

2-ое решение:

Можно в @RequestParam передать ID Высшей категории, проделать вот эту часть, чтобы получить коллекцию подкатегорий:
List<SubCategory> subCategoryList=highCategoryDeserialize.getSubCategories();


Потом же сделать простой Query запрос в БД внутри цикла forEach: "Insert into sub_category......", где я сделаю get нужных мне полей и вставлю в поле high_Category_Id ID из @RequestParam. В данном случае я думаю, что это тоже не лучше решение.
Прошу помочь мне с этой проблемой, должно же у Hibernat-а для этого простого случая найтись надежное и "элегантное" решение.
  • Вопрос задан
  • 1893 просмотра
Пригласить эксперта
Ответы на вопрос 1
Waynes
@Waynes Автор вопроса
В общем рабочих решения по итогу 2. Если кто-нибудь сможет предложить что-нибудь более "достойное" буду очень признателен!

Наш JSON от клиента:

{"subCategories":[{"name":"Детские игрушки"},{"name":"Детское питание"},{"name":"Мамина-рация"}]}


+ Мы еще принимаем ID Высшей категории с помощью : @PathVariable(value = "highCategoryId")

Десериализуем c помощью класса-Wrapper-a :

public class SubCategoryWrapper {

    private List<SubCategory> subCategories;

    /**
     * @return the subCategories
     */
    public List<SubCategory> getSubCategories() {
        return subCategories;
    }

    /**
     * @param subCategories the persons to set
     */
    public void setSubCategories(List<SubCategory> subCategories) {
        this.subCategories = subCategories;
    }

}


Вот собственно сам SubCategory.java:
@Entity
@Table(name = "sub_category")
public class SubCategory extends BaseModel {


    @Column(name = "NAME")
    private String name;


    @ManyToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name = "HIGH_CATEGORY_ID",referencedColumnName = "ID")
    private HighCategory highCategory;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public HighCategory getHighCategory() {
        return highCategory;
    }

    public void setHighCategory(HighCategory highCategory) {
        this.highCategory = highCategory;
    }

    @Override
    public String toString() {
        return "Имя Подкатегории: "+getName();
    }

}


В DAO слое (Туда приход highCategoryId и SubCategoryWrapper ) у нас есть 2 пути :
1:
HighCategory highCategory=entityManager.find(HighCategory.class,highCategoryId);
        highCategory.setSubCategories(subCategories.getSubCategories());

В этом способе в SubCategoryWrapper, в каждом объекте коллекции List не проинициализирована переменная highCategory. Поэтому тут требуется сделать дополнительные манипуляции с сетером в HighCategory:
public void setSubCategories(List<SubCategory> subCategories) {
        this.subCategories = subCategories;
        for(SubCategory subCategory: subCategories){
            subCategory.setHighCategory(this);
        }

Может кто знает, как проинициализировать ее без таких плясок?

2-ой способ:

for (SubCategory subCategory : subCategories.getSubCategories()) {
            entityManager.createNativeQuery("INSERT INTO sub_category(NAME,HIGH_CATEGORY_ID) VALUES(?,?)")
                    .setParameter(1,subCategory.getName())
                    .setParameter(2,highCategoryId).executeUpdate();

        }
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы