我正在尝试删除表单中的一个值。
public class Parameter {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "param_id")
private Long id;
@Column(name = "param_name")
@NotEmpty
private String name;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "param_id", referencedColumnName = "param_id")
private List<ParamValue> values;
}
和
public class ParamValue {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "value_id")
private Long id;
@Column(name = "value_name")
private String name;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name="param_id")
private Parameter parameter;
}
形式:
<form:form method="post" modelAttribute="parameter">
<form:input path="name" />
<c:forEach items="${parameter.values}" var="paramValue" varStatus="uStatus">
<div>
<form:input path="values[${uStatus.index}].id" type="hidden"/>
<form:input path="values[${uStatus.index}].name" type="text" />
<form:input path="values[${uStatus.index}].parameter" type="hidden" />
<button type="button" onclick="$(this).parent().remove();">x</button>
</div>
</c:forEach>
<input type="submit" value="save" class="btn btn-success">
</form:form>
在我的数据库中存在下一个值:
在帕拉姆:
------------------
| id | name |
------------------
| 3 | TestParam |
------------------
在参数值中:
-----------------------------
| id | name | parameter |
-----------------------------
| 116 | value 1 | 3 |
-----------------------------
| 117 | value 2 | 3 |
-----------------------------
| 119 | value 3 | 3 |
-----------------------------
| 152 | value 4 | 3 |
-----------------------------
和控制器:
@Controller(value = "ParamsSave")
@RequestMapping("/params/save")
public class Save extends Base {
@Autowired
private ParamRepo paramRepo;
@ModelAttribute("parameter")
public Parameter getParam(@RequestParam(value = "id", required = false) Long param_id) {
if(param_id == null) {
return new Parameter();
}
Parameter parameter = paramRepo.findById(param_id);
return parameter == null ? new Parameter() : parameter;
}
@GetMapping
public String get(Parameter parameter) {
return getTemplate();
}
@PostMapping
public String post(@Valid Parameter parameter, BindingResult result) {
if(result.hasErrors()) {
return getTemplate();
}
paramRepo.save(parameter);
return "redirect: /";
}
}
如果我删除值"值 2",则会出现错误:
Bean 实例的标识符。参数值从 117 更改为 119;嵌套异常是 org.hibernate.HibernateException: identifier 的豆类实例。参数值从 117 更改为 119
如果我删除最后一个值,则没有任何反应,没有错误,字段不删除。
为什么会发生这种情况,如何从列表中删除值?
我可以在你的代码中看到三个问题:
第一个是关联映射错误。在双向关联中,一侧必须是拥有侧,另一侧是反向侧。正确的映射如下:
@OneToMany(mappedBy = "parameter", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ParamValue> values;
和
@ManyToOne
@JoinColumn(name="param_id")
private Parameter parameter;
请注意,我还删除了cascade=ALL
,因为它在@ManyToOne
的上下文中毫无意义(例如,您不能将ParameterValue
的删除级联到其拥有Parameter
,因为其他ParameterValue
仍然会引用它,从而导致约束冲突异常)。
话虽如此,我严重怀疑是否需要双向关联。为什么不简单地将Parameter.values
映射为:
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "param_id", referencedColumnName = "param_id")
private List<ParamValue> values;
并完全放弃ParamValue.parameter
字段?从您描述的用例来看,无论如何ParamValues
都是Parameter
私有的。
另一个问题是 HTML 表单输入只能与简单值一起使用。我不完全确定以下行的作用:
<form:input path="values[${uStatus.index}].parameter" type="hidden" />
但是,它可能不会按照您的期望进行操作。无论如何,我都不会依赖在Save.post
处理程序中正确设置ParameterValue.parameter
字段。如果选择保留ParameterValue.parameter
字段,则应循环访问Parameter.values
列表,并为每个元素手动设置字段。
最后,使用$(this).parent().remove()
意味着提交的parameter.values[]
数组中将存在间隙(即原本对应于已删除元素的索引将丢失),这与你观察到的删除最后一个值的行为不同是一致的。您绝对应该使用调试器检查Save.post
收到的Parameter.values
内容。