请注意,我已经看过类似的问题,并且已经解释了为什么它们没有为我工作
我有一个简单的Spring boot JPA-Hibernate应用程序,其中User和Address之间是一对一的映射。 (请注意,我没有一对多映射的问题)
用户实体
@Entity
@Table(name = "users")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column
private String name;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
private Address address;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
private Set<Note> notes;
}
地址实体
@Entity
@Table(name = "addresses")
public class Address implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column
private String street;
@Column
private String city;
@JsonIgnore
@OneToOne
@JoinColumn(name = "user_id")
private User user;
}
注释实体
@Entity
@Table(name = "notes")
public class Note implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column
private String date;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
}
我的问题是,每当我调用映射为要获取所有用户的控制器时,我都会得到该地址以及所有相关的注释。但我希望FetchType.LAZY
能够解决这个问题。
我在StackOverflow上阅读了很多问题,提到杰克逊可能是罪魁祸首:
我还读到spring.jpa.open-in-view的默认值可能是罪魁祸首:
所以我尝试了以下选项:
我通过向我的spring.jpa.open-in-view=false
中添加application.properties
来禁用默认打开的视图属性
Could not write JSON: failed to lazily initialize a collection of role error
我认为这是因为杰克逊正在对我的惰性加载对象调用吸气剂,所以我遵循了另一篇文章中的说明,并为杰克逊添加了以下内容,以使惰性加载的集合不予理会:
pom.xml
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
<version>2.9.9</version>
</dependency>
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter converter : converters) {
if (converter instanceof org.springframework.http.converter.json.MappingJackson2HttpMessageConverter) {
ObjectMapper mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
mapper.registerModule(new Hibernate5Module());
}
}
}
}
以上解决方案通过“一对多”映射解决了该问题,但响应中仍关联了“地址”。
我不确定在这里可以做什么。默认登录页面上的用户实体不需要任何地址详细信息,因此我不想将其加载到登录页面上。单击记录后,它将导航到另一个页面,在这里我希望在响应中返回所有延迟加载的对象。
我已经尝试了所有可以在网上找到的内容,但到目前为止仍然没有任何效果。我真的很感谢您的帮助。
一个用户提到它可能是SO另一个问题的重复: Suggested Possible duplicate 我想提到的是,我通过禁用spring.jpa.open-in-view属性但添加了
mapper.registerModule(new Hibernate5Module());
在响应中带回与用户关联的地址。
答案 0 :(得分:1)
您可以看看Jackson Serialization Views。
我已经研究了您尝试过的Hibernate5模块,它具有一些有趣的功能...但是没有人可以为您解决这个问题。
顺便说一句,我通常通过不返回实体作为响应而是返回DTO来解决此问题。
答案 1 :(得分:1)
它的工作方式与JPA规范相同:-
请参考以下网址 https://javaee.github.io/javaee-spec/javadocs/javax/persistence/FetchType.html
LAZY提取策略只是一个提示(如javadoc所述,可以延迟获取数据)..不是强制性操作。
急切是强制性的(因为javadoc说必须急切地获取数据)。
答案 2 :(得分:1)
问题是杰克逊在编写JSON时会触发初始化,因此请不要编写当前字段(地址)。但是您不应该使用@jsonIgnore
,因此在其他地方您可以返回Eager
obj。
您可以使用@jsonView
注释,该注释可以在不同请求下为同一obj提供不同的JSON。您可以看一下以下示例:
创建视图类:
public class ViewFetchType {
static class lazy{ }
static class Eager extends lazy{ }
}
注释您的实体
@Entity
public class User {
@Id
@JsonView(ViewFetchType.Lazy.class)
private String id;
@JsonView(ViewFetchType.Eager.class)
@OneToOne( fetch = FetchType.LAZY)
private Address address ;
}
在您的控制器中指定FetchType
类:
public class UserController {
private final UserRepository userRepository;
@Autowired
UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@RequestMapping("get-user-details")
@JsonView(ViewFetchType.Eager.class)
public @ResponseBody Optional<User> get(@PathVariable String email) {
return userRepository.findByEmail(email);
{
@RequestMapping("get-all-users")
@JsonView(ViewFetchType.Lazy.class)
public @ResponseBody List<User> getUsers() {
return userRepository.findAll();
}
}
中获得灵感的答案