我有这两个实体。
Name Size Records
File1 1013 105727
File2 990 104230
File3 1520 110542
File4 2198 115369
File5 2026 113430
File6 1844 112105
File7 1216 108159
File8 1520 110408
File9 1013 105359
File10 1317 108428
File11 1925 112553
File12 1449 109456
File13 1803 111436
File14 2036 115937
File15 2043 116383
@Entity
public class Person {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne(cascade=CascadeType.ALL)
private Location location;
public Person() {
}
我也有这个控制器。
@Entity
public class Location {
@Id @GeneratedValue
private Long id;
private String place;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "location")
private Set<Person> persons;
public Location() {
}
此存储库。
@Controller
public class PersonController {
private final PersonRepository repo;
public PersonController(PersonRepository repo) {
this.repo = repo;
}
@GetMapping("/")
public String newPerson(Person person){
return "home";
}
@PostMapping("/")
public String newPerson(Person person, BindingResult result){
repo.save(person);
return "redirect:/person";
}
我也有这种支持形式。
@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
Optional<Person> findFirstByName(String name);
}
当我提交一些数据时,一切正常。保存Person对象,Location对象也是如此。
但是当我添加
<form action="#" th:action="@{/}" th:object="${person}" method="post">
<table>
<tr>
<td>Name:</td>
<td><input type="text" th:field="*{name}" /></td>
</tr>
<tr>
<td>Location:</td>
<td><input type="text" th:field="*{location}" /></td>
</tr>
<tr>
<td><button type="submit">Submit</button></td>
</tr>
</table>
</form>
当我提交相同的确切表单时,Location对象不会保存到数据库。为什么只添加此存储库会导致此问题,解决方案是什么?感谢。
答案 0 :(得分:1)
您可以修复表单以编写位置属性的属性:
<td><input type="text" th:field="*{location.place}" /></td>
此外,您不必在存储库中添加@Repository
注释。
答案 1 :(得分:1)
详细说明为什么工作起作用:
表单绑定使用ConversionService
。 Spring Data从String
- >注册转换链。 id type - &gt;每个存储库托管域类的实体类型。因此,当您添加存储库时,String
作为Person.location
的值提交将被解释为已存在位置的标识符。它将导致使用为名为location
的字段提交的值的by-id查找。
这在以下场景中很方便:假设您Location
基本上是数据库中保存的实例的精选列表,例如:一系列国家。他们你不想随意创建新的,而是从整体列表中选择一个,这基本上归结为必须使用下拉框而不是文本字段。
从概念上讲,不一致的基本事物是级联(因为它们表示组合,即Location
是聚合的一部分)并且LocationRepository
作为存储库的存在导致托管类型隐式成为聚合根(这是基本的DDD)。
这反过来意味着您必须单独处理该实例的生命周期。一个潜在的解决方案是检查绑定到Location
的{{1}},检查具有Person
的实例是否已经存在(通过place
上的查询方法),如果是,用加载的那个替换绑定的那个,或者只用原始实例调用LocationRepository
来创建一个新实例。
我仍然没有完全购买原始尝试创建正确的 LocationRepository.save(…)
,因为您的模板Spring Framework无法猜测您提交的内容为Location
实际上应该是location
。所以我假设您看到一个place
实例正在创建,但是完全为空且Location
实际上有错误,声称它无法将BindingResult
表单字段转换为{{ 1}}。