gpt4 book ai didi

java - 如何阻止 hibernate 在 ManyToMany 映射中插入表?

转载 作者:行者123 更新时间:2023-12-02 10:26:02 25 4
gpt4 key购买 nike

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

我确实尝试弄乱“cascade=CascadeType.ALL”设置,但通常得到“对象引用未保存的 transient 实例 - 在刷新之前保存 transient 实例: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 的东西:

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 (?)

I do not want it to be inserting into ingredient table because I have already populated the table with 1000 ingredient names. Realistically I would just want to insert into shampoo_ingredients with the key of the given ingredient.

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

@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";

}
}

洗发水 DAO

@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 是您从未保存过的"new"对象。所以 hibernate 告诉你:“在你加入他们之前,你必须保存他们”。

另一方面,由于您有 CascadeType.All hibernate 会尝试插入这些"new"对象

你要做的就是在数据库中搜索成分,然后设置它们。

我的意思是这样的:

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

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

希望有用

安杰洛

关于java - 如何阻止 hibernate 在 ManyToMany 映射中插入表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53952565/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com