问题:我的Web MVC应用程序正在插入成分表。我不想这样做,因为我已经在该表中填充了1000种不同的洗发精成分。

我确实尝试弄乱“ cascade = CascadeType.ALL”设置,但通常会收到“对象引用了一个未保存的瞬态实例-在刷新之前保存该瞬态实例:com.app.entity.Ingredient”。但是我真的不确定那是否可以解决任何问题。

Image of Console

DB DIAGRAM

在提交结果用户之后并且将其插入数据库之前,输出toString():

Shampoo [id=0, name=sas, company=Company [id=0, name=asassa], ingredients=[Ingredient [id=0, name=1-Dodecene, shampoos=null], Ingredient [id=0, name=Acetylated, shampoos=null]]]


冬眠的东西:

Hibernate: insert into company (company_name) values (?)
Hibernate: insert into shampoo (shampoo_company, shampoo_name) values (?, ?)



Hibernate: insert into ingredient (ingredient_name) values (?)
Hibernate: insert into ingredient (ingredient_name) values (?)

  
  我不希望将其插入成分表,因为我已经在表格中填充了1000个成分名称。实际上,我只想用给定成分的键插入shampoo_ingredients中。


Hibernate: insert into shampoo_ingredients (fk_shampoo, fk_ingredient) values (?, ?)
Hibernate: insert into shampoo_ingredients (fk_shampoo, fk_ingredient) values (?, ?)


洗发水实体

@Entity
@Table(name="shampoo")
public class Shampoo {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="shampoo_id")
    private int id;

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

    @OneToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="shampoo_company")
    private Company company;

    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable(
            name="shampoo_ingredients",
            joinColumns=@JoinColumn(name="fk_shampoo"),
            inverseJoinColumns=@JoinColumn(name="fk_ingredient")
            )
    private List<Ingredient> ingredients;

    public Shampoo() {

    }



    public Shampoo(String name) {
        this.name = name;
    }



    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }


    public List<Ingredient> getIngredients() {
        return ingredients;
    }

    public void setIngredients(List<Ingredient> ingredients) {
        this.ingredients = ingredients;
    }



    @Override
    public String toString() {
        return "Shampoo [id=" + id + ", name=" + name + ", company=" + company + ", ingredients=" + ingredients + "]";
    }


}


成分实体

@Entity
@Table(name="ingredient")
public class Ingredient {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="ingredient_id")
    private int id;

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

    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable(
            name="shampoo_ingredients",
            joinColumns=@JoinColumn(name="fk_ingredient"),
            inverseJoinColumns=@JoinColumn(name="fk_shampoo")
            )
    private List<Shampoo> shampoos;

    public Ingredient() {

    }


    public Ingredient(String name) {
        this.name = name;
    }


    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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


    public List<Shampoo> getShampoos() {
        return shampoos;
    }

    public void setShampoos(List<Shampoo> shampoos) {
        this.shampoos = shampoos;
    }


    @Override
    public String toString() {
        return "Ingredient [id=" + id + ", name=" + name + ", shampoos=" + shampoos + "]";
    }


}


洗发水控制器

@Controller
@RequestMapping("/shampoo")
public class ShampooController {

    //inject DAO into controller
    @Autowired
    private ShampooDAO shampooDAO;
    @Autowired
    private CompanyDAO companyDAO;
    @Autowired
    private IngredientDAO ingredientDAO;
    @Autowired
    private ConversionService cs;
    @RequestMapping("/list")
    public String listShampoos(Model theModel) {

        //get shampoo from DAO
        List<Shampoo> theShampoos = shampooDAO.getShampoos();

        //add shampoo to model
        theModel.addAttribute("shampoos", theShampoos);
        return "list-shampoos";
    }

    @GetMapping("/showFormForAdd")
    public String showFormForAdd(Model theModel, ModelMap modelMap) {
        //create model attribute to bind form data

        Shampoo theShampoo = new Shampoo();
        modelMap.addAttribute("shampoo", theShampoo);


        List<Ingredient> theIngredients = ingredientDAO.getIngredients();

        modelMap.addAttribute("ingredient", theIngredients);




        return "shampoo-form";
    }

    @PostMapping("/saveShampoo")
    public String saveShampoo(@ModelAttribute("shampoo") Shampoo theShampoo) {


        System.out.println(theShampoo.getIngredients());
        System.out.println(theShampoo.toString());
        shampooDAO.saveShampoo(theShampoo);
        return "redirect:/shampoo/list";

    }
}


洗发精

@Repository
public class ShampooDAOImpl implements ShampooDAO {

    @Autowired
    private SessionFactory sessionFactory;

    @Transactional
    public List<Shampoo> getShampoos() {

        //get current hibernate session
        Session currentSession = sessionFactory.getCurrentSession();
        //create query
        Query<Shampoo> theQuery = currentSession.createQuery("from Shampoo", Shampoo.class);
        //execute query and get result list
        List<Shampoo> shampoos = theQuery.getResultList();
        //return list of shampoo
        return shampoos;
    }

    @Transactional
    public void saveShampoo(Shampoo theShampoo) {

        Session currentSession = sessionFactory.getCurrentSession();

        currentSession.save(theShampoo);

    }

}


洗发水形式

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>


<!DOCTYPE html>
<html>
<head>
    <title>Add New Shampoo</title>
    <script src="${pageContext.request.contextPath}/resources/jquery-3.3.1.min.js"></script>
    <script src="${pageContext.request.contextPath}/resources/chosen.jquery.js"></script>


    <link type="text/css" href="<%=request.getContextPath() %>/resources/chosen.css" rel="stylesheet"/>
<script>

$(document).ready(function(e){
    // first initialize the Chosen select
    $('.test').chosen();

});


</script>

</head>
<body>

        <form:form cssClass="form" action="saveShampoo" modelAttribute="shampoo" method="POST">

            <table>
                <tbody>
                    <tr>
                        <td><label>Name:</label></td>
                        <td><form:input path="name" /></td>
                    </tr>
                    <tr>
                        <td><label>Company:</label></td>
                        <td><form:input path="company" /></td>
                    </tr>

                    <tr>
                        <td><label>Ingredients:</label></td>
                        <td><form:select cssClass="test" multiple="true" path="Ingredients" >
                            <form:options items="${ingredient}" itemValue="name" itemLabel="name" />

                            </form:select></td>
                    </tr>

                </tbody>

            </table>
            <input id= "submit" type="submit" value="Save"/>
        </form:form>

</body>

</html>

最佳答案

关键是,当您尝试加入实体香波和成分时,必须从数据库中获取它们。

假设您创建了一种新的洗发水。你可以做:

Shampoo s = new Shampoo();
//All your own stuffs about Shampoo object


现在,您想加入洗发水和成分;并假设您想加入的配料名称是“ IngrA”和“ IngrB”,您不能这样做:

Ingredient a = new Ingredient();
a.setName("IngrA");
Ingredient b = new Ingredient();
b.setName("IngrB");
List<Ingredient> ingrs = new ArrayList<>(2);
ingrs.add(a);
ingrs.add(b);
s.setIngredients(ingrs);
repository.save(s); //Error will be thrown here; If you have CascadeType.All an insert will be done


为什么会有错误?因为根据Hibernate,ab是“新”对象,所以您从未保存过。因此,休眠告诉您:“在加入他们之前,您必须保存他们”。

另一方面,由于您有CascadeType.All休眠,休眠会尝试插入这些“新”对象

您必须做的是在数据库中搜索成分,然后进行设置。

我的意思是这样的:

Ingredient a = ingredientDao.findByName("IngrA");
Ingredient b = ingredientDao.findByName("IngrB");
List<Ingredient> ingrs = new ArrayList<>(2);
if(a!=null)
   ingrs.add(a);
if(b!=null)
   ingrs.add(b);
s.setIngredients(ingrs);
repository.save(s); //No error will be thrown here


为什么没有错误?因为您从DB检索了成分,现在它们不再分离了。

我希望它有用

安杰洛

07-24 09:44
查看更多