当我有用户并且他们有其他用户作为朋友时,我想让应用程序类似于facebook。因此,我创建了一个实体用户
,该实体本身有很多关系,它们也可以邀请对方加入好友列表。不幸的是,当我想获取具有好友邀请的用户时,我遇到了此错误:
Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: java.util.ArrayList[0]->com.pk.thesis.devbook.models.dto.UserDTO["invitedFriends"]->java.util.ArrayList[0]->com.pk.thesis.devbook.models.dto.UserDTO["invitedFriends"]->java.util.ArrayList[0]-
... (it goes forever)
>com.pk.thesis.devbook.models.dto.UserDTO["invitedFriends"]->java.util.ArrayList[0]with root cause
我的缩短用户实体类:
@Data
@Entity
@Table( name = "users",
uniqueConstraints = {
@UniqueConstraint(columnNames = "username"),
@UniqueConstraint(columnNames = "email")
})
@JsonIdentityInfo(generator= ObjectIdGenerators.UUIDGenerator.class, property="@id")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
@Size(max = 40)
private String username;
//other things...
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name="tbl_friends",
joinColumns=@JoinColumn(name="personId"),
inverseJoinColumns=@JoinColumn(name="friendId")
)
private List<User> friends;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinTable(name="tbl_friends",
joinColumns=@JoinColumn(name="friendId"),
inverseJoinColumns=@JoinColumn(name="personId")
)
private List<User> friendOf;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinTable(name="tbl_invites_to_friends",
joinColumns=@JoinColumn(name="personId"),
inverseJoinColumns=@JoinColumn(name="invited_personId")
)
@JsonIgnoreProperties("invitationsToFriends")
private List<User> invitedFriends;
@JsonIgnore
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinTable(name="tbl_invites_to_friends",
joinColumns=@JoinColumn(name="invited_personId"),
inverseJoinColumns=@JoinColumn(name="personId")
)
@JsonIgnoreProperties("invitedFriends")
private List<User> invitationsToFriends;
}
正如你所看到的,我试图让它变得懒惰,也尝试了@JsonIgnore注释,但什么都不起作用。有什么建议吗?
返回UserDTO的方法(将User映射到UserDTO)
public UserDTO getUserDTO(String username) {
return userRepository.findByUsername(username)
.map(u -> modelMapper.map(u, UserDTO.class))
.orElseThrow(() -> new UsernameNotFoundException("User not
found"));
}
UserDTO通过org.modelmapper.ModelMapper映射
public class UserDTO {
private String username;
private String firstname;
private String lastname;
private String email;
private List<UserDTO> invitedFriends;
private List<UserDTO> invitationsToFriends;
}
多亏了评论部分的答案,我找到了一种方法。我制作了另一个带有附加日期字段的实体InvitationsToFriend,并通过OneTo多国关系将其与我的用户实体连接起来。我还使用我需要的字段(用户名、名字、姓氏)创建了Reduce edUserDTO和Reduce edInvitationsToFriendsDTO。
我的用户类别:
@Entity
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Size(max = 40)
private String username;
@Size(max = 120)
private String password;
@Column
private String firstname;
@Column
private String lastname;
@OneToMany(mappedBy="to")
private List<InvitationsToFriends> invitationsToFriends;
@OneToMany(mappedBy="from")
private List<InvitationsToFriends> invitedFriends;
}
邀请朋友:
@Entity
public class InvitationsToFriends implements Serializable{
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
@ManyToOne( fetch = FetchType.LAZY)
@JoinColumn(name="from_user_fk")
private User from;
@ManyToOne( fetch = FetchType.LAZY)
@JoinColumn(name="to_user_fk")
private User to;
@Column(name = "invitation_date")
private Date invitationDate;
}
用户:
@Data
public class UserDTO {
private String username;
private String firstname;
private String lastname;
private List<ReducedInvitationsToFriendsDTO> invitedFriends;
private List<ReducedInvitationsToFriendsDTO> invitationsToFriends;
}
将生命还原为朋友,并还原为:
@Data
public class ReducedInvitationsToFriendsDTO {
private ReducedUserDTO from;
private ReducedUserDTO to;
}
@Data
public class ReducedUserDTO {
private String username;
private String firstname;
private String lastname;
}
现在,响应json如下所示:
username: "username"
firstname: "firstname"
lastname: "lastname"
email: "email@email.com"
invitedFriends: [
from: {username: "username", firstname: "firstname", lastname: "lastname"}
to: {username: "invitedUsername", firstname: "invitedFirstname", lastname: "invitedLastName"}]
要避免无限递归,只需使用注释,但要使用所有嵌套多对多字段的数组,例如:
@JsonIgnoreProperties({"friends", "friendsOf", "invitedFriends", "invitedFriendsOf"})
@ManyToMany
@JoinTable(...)
private Set<Person> friends;
然后,为了避免出现异常。fasterxml。杰克逊。数据绑定。JsonMappingException:未能延迟初始化角色的集合 将上升,您可以使用存储库的查询方法上的EntityGraph参数AttributePath,该参数也设置为这些字段名称的数组,在一个查询中填充它们的值:
@Transactional(readOnly = true)
public interface PersonRepo extends JpaRepository<Person, Long> {
@EntityGraph(attributePaths = {"friends", "friendsOf", "invitedFriends", "invitedFriendsOf"})
Optional<Person> getById(Long aLong);
}
在这种情况下,将设置所有字段值,避免递归,并且您将能够在控制器中获得正确的结果:
@GetMapping("/{id}")
public Person get(@PathVariable Long id) {
return personRepo.getById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Person not found"));
}
然后你可能想要获取所有的人。考虑到一个人的数据非常大,在一个列表中获取所有相关朋友的所有人是不正确的。最好只获取每个人的基本字段。在这种情况下,您可以使用简单的DTO:
@Value
public class PersonDto {
private long id;
private String name;
private String email;
public PersonDto(Person person) {
this.id = person.getId();
this.name = person.getName();
this.email = person.getEmail();
}
}
并将Person映射到它:
@GetMapping
public List<PersonDto> getAll() {
return personRepo.findAll().stream().map(PersonDto::new).collect(Collectors.toList());
}
由于这种映射,您将避免出现异常com。fasterxml。杰克逊。数据绑定。JsonMappingException也是如此。
此答案中使用的实体人员:
@Data
@EqualsAndHashCode(of = "email")
@ToString(of = {"id", "name", "email"})
@Entity
@Table(name = "people")
public class Person {
@Id
@GeneratedValue
private Long id;
@Column(nullable = false, length = 32)
private String name;
@NaturalId
@Column(nullable = false, length = 32)
private String email;
@JsonIgnoreProperties({"friends", "friendsOf", "invitedFriends", "invitedFriendsOf"})
@ManyToMany
@JoinTable(name = "friends", joinColumns = @JoinColumn(name = "person_id"), inverseJoinColumns = @JoinColumn(name = "friend_id"))
private Set<Person> friends;
@JsonIgnoreProperties({"friends", "friendsOf", "invitedFriends", "invitedFriendsOf"})
@ManyToMany
@JoinTable(name = "friends", joinColumns = @JoinColumn(name = "friend_id"), inverseJoinColumns = @JoinColumn(name = "person_id"))
private Set<Person> friendsOf;
@JsonIgnoreProperties({"friends", "friendsOf", "invitedFriends", "invitedFriendsOf"})
@ManyToMany
@JoinTable(name = "invited_friends", joinColumns = @JoinColumn(name = "person_id"), inverseJoinColumns = @JoinColumn(name = "friend_id"))
private Set<Person> invitedFriends;
@JsonIgnoreProperties({"friends", "friendsOf", "invitedFriends", "invitedFriendsOf"})
@ManyToMany
@JoinTable(name = "invited_friends", joinColumns = @JoinColumn(name = "friend_id"), inverseJoinColumns = @JoinColumn(name = "person_id"))
private Set<Person> invitedFriendsOf;
}
我的工作演示-您可以在IDE中运行它,连接到H2数据库(使用这种方法)以查看其数据。如果您的IDE是IntelliJ IDEA,则可以直接从demo文件运行demo请求。http。多亏了log4jdbc spring boot starter,您可以在应用程序日志中看到所有SQL查询。
问题内容: 另一个hibernate问题…:P 使用Hibernate的Annotations框架,我有一个实体。每个人都可以有一个朋友的集合:其他的集合。但是,我还无法弄清楚如何在由s 列表组成的类中创建多对多关联(使用用户友好中间表)。 这是User类及其注释: 用户- 朋友映射表只有两列,这两列都是该表列的外键。两列是(应映射到当前用户)和(指定当前用户的朋友的ID)。 问题是,即使我已经预
DBSchema-2表(用户和角色)具有多对多关系,并由postgres中的中间表(用户角色)桥接。我想获取所有角色和创建它的人的姓名。名称在用户表中可用,但所有其他详细信息在角色表中。Roles表中有一个由创建人(创建角色的人的用户id)创建的字段。 我正在尝试构建一个GET请求,以查看给定id的所有角色以及创建id的人的姓名 实体类Users1.java 实体类角色。JAVA 角色。存储库类
问题内容: 问题在标题中: 如何将多对多关系表作为实体? 问题答案: 我会说,你的问题很合理。看看这个文档部分:第24章最佳实践。摘录: 不要使用外来关联映射: 真正的多对多关联的实际测试案例很少见。大多数时候,您需要存储在“链接表”中的其他信息。在这种情况下,最好将两个一对多关联用于中间链接类。实际上,大多数关联是一对多和多对一的。因此,在使用任何其他关联样式时,您应谨慎进行。 我们正在处理的方
救命啊!我只在一对多关系数据库中插入POJO时遇到问题。我有POJO和误解如何插入数据库中的所有列表??? 请帮帮我伙计们!
我在一个laravel控制器中运行以下代码, 但是我似乎从服务器上得到了以下错误, {“error”:{“type”:“ErrorException”,“message”:“preg_replace():参数不匹配,模式为字符串,而替换为数组”,“file”:“/Users/S/Sites/app api/vendor/laravel/framework/src/illumb/Support/he