V
V
Valentine2016-04-06 00:38:46
Java
Valentine, 2016-04-06 00:38:46

How to save a collection of objects using JPA?

Good day to all! My problem is this: JSON comes from the client:

{"name":"Строительство","subCategories":[{"name":"электроинструменты"},{"name":"грузовые машины"}]}

That is, here I am passing the name of the Highest category, and an array of subcategories with parameters. It is necessary to save subcategories in the database. Here are the entities themselves:
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;
    }

So far I have come up with 2 ways to solve this problem, but they are so clumsy that I think there are more adequate
solutions: 1st solution:
@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 is a variable of the HighCategoryDeserialize class , which is exactly the same as HighCategory. This was done so that Jackson could also deserialize the List, which in HighCateogry stands as @JsonIngnore, so that additional information is not pulled out during a Get request. That is, here I actually copy HighCategoryDeserialize to HighCategory, because HighCategory is memorized and Hibernate can work with it. Then I set this HighCategory to all subcategories. Well, in the DAO layer I already do:
@Override
    public String addSubCategory(List<SubCategory> subCategories) {
        String resultOfOperation;

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

        return resultOfOperation="Operation complete!";
    }

But the approach is this, it creates the same Highest category, which is completely out of my hands + in my opinion, Hibernat has some more adequate solution.
2nd solution:
You can pass the ID of the Top category to @RequestParam , do this part to get a collection of subcategories:
List<SubCategory> subCategoryList=highCategoryDeserialize.getSubCategories();

Then make a simple Query query to the database inside the forEach loop: "Insert into sub_category ......", where I will get the fields I need and insert the high_Category_Id ID from @RequestParam into the high_Category_Id field. In this case, I think that this is also not the best solution.
Please help me with this problem, Hibernat should have a reliable and "elegant" solution for this simple case.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
V
Valentin, 2016-04-07
@Waynes

In general, working solutions for the total 2. If someone can offer something more "worthy" I will be very grateful!
Our JSON from the client:
+ We also accept a Top Category ID with : @PathVariable(value = "highCategoryId")
Deserialize with a Wrapper class :

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

}

Here is the SubCategory.java itself :
@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();
    }

}

In the DAO layer ( where highCategoryId and SubCategoryWrapper come in) we have 2 ways:
HighCategory highCategory=entityManager.find(HighCategory.class,highCategoryId);
        highCategory.setSubCategories(subCategories.getSubCategories());

In this way, in the SubCategoryWrapper, the highCategory variable is not initialized in each List collection object. Therefore, here it is required to do additional manipulations with the seter in HighCategory :
public void setSubCategories(List<SubCategory> subCategories) {
        this.subCategories = subCategories;
        for(SubCategory subCategory: subCategories){
            subCategory.setHighCategory(this);
        }

Maybe someone knows how to initialize it without such dances?
for (SubCategory subCategory : subCategories.getSubCategories()) {
            entityManager.createNativeQuery("INSERT INTO sub_category(NAME,HIGH_CATEGORY_ID) VALUES(?,?)")
                    .setParameter(1,subCategory.getName())
                    .setParameter(2,highCategoryId).executeUpdate();

        }

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question