2017-06-20 38 views
2

我有这两个实体。添加Spring Data Repository禁用功能

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

} 

我也有这种支持形式。

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

这一切工作正常,当我提交一些数据。 Person对象被保存,Location对象也被保存。

但是当我添加

@Repository 
public interface LocationRepository extends JpaRepository<Location, 
Long> {) 

位置对象不保存到数据库中,当我提交相同的确切形式。为什么只是添加这个存储库会导致这个问题,解决方案是什么?谢谢。

+1

你可以试试'th:field =“* {location.place}”'? – ledniov

+0

谢谢。这确实解决了这个问题。我认为这是我错过了一些小事。仍然有点想知道为什么表单在没有LocationRepository的情况下工作?我猜测,因为当仓库创建时,Location对象期望一个ID可能被传递。 – Jon

+0

当你填写表单时,并不需要储存库,它们被用来储存数据 – ledniov

回答

1

您解决对子级的形式,以写位置属性的属性:

<td><input type="text" th:field="*{location.place}" /></td> 

你也不必把@Repository注释你的资料库。

1

解释为何工作的事情,因为他们的工作:

形式结合使用ConversionService。 Spring Data为每个存储库管理的域类注册一个从String - > id type - >实体类型的转换链。因此,当您添加存储库时,作为Person.location的值提交的String将被解释为已存在位置的标识符。它将通过为名为location的字段提交的值进行带-id的查找。

这在以下情况下很方便:假设你是Location基本上是保存在数据库中的实例的策划列表,例如,国家名单。他们你不想任意创建新的,而是从整个列表中选择一个,这基本上归结为不得不使用下拉框而不是文本字段。因此从概念上讲,最根本的事情是级联(因为它们表示组合,即Location是聚集的一部分),LocationRepository作为存储库的存在会导致托管类型隐式成为聚合根(这是是基本的DDD)。

这反过来意味着你必须单独处理那个实例的生命周期。一个可能的解决方案是检查绑定到PersonLocation,检查具有place的实例是否已经存在(通过LocationRepository上的查询方法),如果是,则用原始实例替换与加载的实例绑定的实例或只调用LocationRepository.save(…)创造一个新的。

我还是不完全买,原来企图从您的模板Spring框架创建正确Location至于是不是能猜到您提交什么作为location应该是place实际。所以我假设你看到一个Location实例被创建,但是完全是空的,并且BindingResult实际上带有错误,声称它不能将location表单字段转换为Location的实例。

+0

谢谢。我很欣赏这种回应。但是我只是在表单上再次尝试没有'LocationRepository'并且只用'th:field =“* {location}”''的例子,并且它确实有效。我正在查看MySQL中的数据库,实际上有一个'Person'对象被保存到一个人员表中,其中一个外部关键字被保存到一个位置表中的'Location'对象中。试试看。 – Jon

相关问题