Kill the collection field composed of attribute ID in POJO

Use SpringConverter to optimize the association between Ids and Ids

We will encounter this problem during project development. List ingredients; List ingredients; It is also a collection of principles. One back-end likes it and the other front-end likes it. These two are often written in a POJO. According to the relationship of objects, we prefer the first one. Database query is not good!

1. Problem description

1.1. The form submitted multiple same name values

Take a pancake fruit as an example. Making pancake fruit requires a variety of raw materials, so you have the form data below

      <input type="checkbox" name="ingredients" th:value="${item.id}" />
      <input type="checkbox" name="ingredients" th:value="${item.id}" />
      <input type="checkbox" name="ingredients" th:value="${item.id}" />
       <input type="checkbox" name="ingredients" th:value="${item.id}" />

1.2. We generally use array to receive

For example, get the ID array and delete it in batch. Now let's add the ID set of raw materials to the pancake fruit

package com.wnx.toca.domain;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

/**
 * pancake rolled with crisp fritter
 * @author wangnaixing
 * @Classname ChineseHamburger
 * @Description TODO
 * @Date 2021/12/14 22:43
 * @Created by wangnaixing
 */
@Data
public class ChineseHamburger implements Serializable {
    /**
     * Auto increment primary key
     */
    private Long id;
    /**
     * Producer name
     */
    private String name;
    /**
     * Creation time
     */
    private Date created;

    //=======Additional properties==========//
    /**
     * Raw material collection
     */
    List<Long> ingredients;
    //=======Additional properties==========//

}

1.3. Now we want to save the pancake fruit

Our general idea must be:

  • Save the pancake fruit information first
  • Then add the correlation between pancake fruit and raw materials

2. My previous handling

Here, I have used Spring's JdbcTemplate as the persistence layer operation as an example

2.1 define the method of querying raw materials by ID on the Dao of raw materials

    /**
     * Query pancake fruit raw materials according to ID
     * @param id
     * @return
     */
    Ingredient findById(Long id);
  /**
     * Query pancake fruit raw materials according to ID
     * @param id
     * @return
     */
    @Override
    public Ingredient findById(Long id) {
        return jdbcTemplate.queryForObject("select id,name,type from ingredient where id = ?",this::mapRowToIngredient,id);
    }

2.2. Define the method of adding pancake fruit

  • Operate JDBC template to add pancake fruit to obtain the self increasing primary key

  • Inject the Serivce of raw materials, traverse the raw material ID set of pancake fruit attributes, and query the raw materials according to the ID

  @Repository
public class JdbcChineseHamburgerDaoImpl implements ChineseHamburgerDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private IngredientService ingredientService;

  /**
     * Add pancake fruit
     * @param chineseHamburger
     * @return
     */
    @Override
    public ChineseHamburger save(ChineseHamburger chineseHamburger) {
        //Add pancake fruit table record first
        long chineseHamburgerId = this.saveChineseHamburger(chineseHamburger);

        List<Long> ingredientIds = chineseHamburger.getIngredients();
        List<Ingredient> ingredientList = new ArrayList<>();

        for (Long ingredientId : ingredientIds) {
            //Call the persistence layer to query the pancake fruit raw materials
            Ingredient ingredient = ingredientService.findById(ingredientId);
            ingredientList.add(ingredient);
        }

        //Add the record of pancake fruit and pancake fruit seasoning relationship table
        ingredientList.forEach(ingredient -> {this.saveChineseHamburgerIngredientRelation(ingredient,chineseHamburgerId);});

        return chineseHamburger;
    }
}

2.3 extraction method

    /**
     * Save the pancake fruit and return the self incremented primary key
     * @return
     */
    private long saveChineseHamburger(ChineseHamburger chineseHamburger){
        chineseHamburger.setCreated(new Date());
        KeyHolder keyHolder = new GeneratedKeyHolder();

        //DDL based on the definition of PreparedStatementCreator
        PreparedStatementCreator creator =
                new PreparedStatementCreatorFactory(
                        "insert into chinese_hamburger(name,created) values(?,?)",
                        Types.VARCHAR, Types.TIMESTAMP
                ).newPreparedStatementCreator(
                        Arrays.asList(chineseHamburger.getName(),
                                new Timestamp(chineseHamburger.getCreated().getTime())));
        jdbcTemplate.update(creator, keyHolder);
        //Get the self incrementing primary key and return
        return keyHolder.getKey().longValue();
    }

    /**
     * Add the record of pancake fruit and pancake fruit seasoning relationship table
     * @param ingredient
     * @param chineseHamburgerId
     */
    private void saveChineseHamburgerIngredientRelation(Ingredient ingredient,long chineseHamburgerId){

        jdbcTemplate.update(
                "insert into chinese_hamburger_ingredient_relation (chinese_hamburger_id, ingredient_id) " +
                        "values (?, ?)",
                chineseHamburgerId, ingredient.getId());
    } 

3. New method: Converter converter processing

Can I write a principle set of List < increment > instead of List when the domain is set? This part of the code is obviously disgusting every time it is converted according to the ID. Converter converter can solve this problem.

3.1. Define custom converter

package com.wnx.toca.converter;


import com.wnx.toca.domain.Ingredient;
import com.wnx.toca.serivce.IngredientService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;


/**
 * Pancake fruit material and pancake fruit ID converter
 * @author wangnaixing
 */
@Component
public class IngredientByIdConverter implements Converter<String, Ingredient> {
  @Autowired
  private IngredientService ingredientService;

  @Override
  public Ingredient convert(String id) {
    if (StringUtils.isNotBlank(id)){
      return ingredientService.findById(Long.parseLong(id));
    }
    return null;
  }

}

3.2. Modify domain

package com.wnx.toca.domain;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

/**
 * pancake rolled with crisp fritter
 * @author wangnaixing
 * @Classname ChineseHamburger
 * @Description TODO
 * @Date 2021/12/14 22:43
 * @Created by wangnaixing
 */
@Data
public class ChineseHamburger implements Serializable {
    /**
     * Auto increment primary key
     */
    private Long id;
    /**
     * Producer name
     */
    private String name;
    /**
     * Creation time
     */
    private Date created;

    //=======Additional properties==========//
    /**
     * Raw material collection
     */
    List<Ingredient> ingredients;
    //=======Additional properties==========//

}

3.3 printing results

Keywords: Java Spring Boot

Added by itguysam on Wed, 15 Dec 2021 10:39:43 +0200