Spring - 从Web表单更新OneToMany集合

时间:2018-04-18 11:27:20

标签: spring jpa

我正在尝试删除表单中的一个值。

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

在ParamValue中:

-----------------------------
| 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”,则出现错误:

  

beans.ParamValue实例的标识符从117更改为   119;嵌套异常是org.hibernate.HibernateException:identifier   beans.ParamValue的实例从117更改为119

如果我删除了最后一个值,则没有任何反应,没有错误,字段也没有删除。

为什么会发生这种情况,如何从列表中删除值?

1 个答案:

答案 0 :(得分:0)

我可以在您的代码中看到三个问题:

第一个是关联映射是错误的。在双向关联中,一方必须是拥有方,另一方必须是反向方。正确的映射如下:

@OneToMany(mappedBy = "parameter", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ParamValue> values;

@ManyToOne
@JoinColumn(name="param_id")
private Parameter parameter;

请注意,我也删除了cascade=ALL,因为它在@ManyToOne的上下文中没有任何意义(您无法将ParameterValue级联删除到其拥有{{1}例如,因为其他Parameter仍会引用它,导致约束违例异常)。

话虽如此,我对是否需要双向关联存在严重怀疑。为什么不简单地将ParameterValue映射为:

Parameter.values

并完全删除@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "param_id", referencedColumnName = "param_id") private List<ParamValue> values; 字段?根据您所描述的用例来判断ParamValue.parameter <{1}} 私有ParamValues无论如何。

另一个问题是HTML表单输入只能与简单值一起使用。我不完全确定以下行是做什么的:

Parameter
然而,有可能它没有达到预期的效果。无论如何,我不会依赖<form:input path="values[${uStatus.index}].parameter" type="hidden" /> 处理程序中正确设置的ParameterValue.parameter字段。如果您选择保留Save.post字段,则应迭代ParameterValue.parameter列表,并为每个元素手动设置字段。

最后,使用Parameter.values表示提交的$(this).parent().remove()数组中存在间隙(即原始对应于已删除元素的索引将丢失),这与您删除的观察结果一致最后一个值表现不同。您应该使用调试器检查parameter.values[]收到的Parameter.values的内容。