假设我们有User实体类。用户可以与其他用户成为朋友。如何在不创建名为Connection的新实体或在数据库中创建多个条目的情况下映射此自引用集合字段?
@Entity
public class User {
...
@ManyToMany
private Collection<User> friends;
...
}
USER_ID-FRIEND_ID
1 - 2
2 - 1 (duplicate... I don't need it)
答案 0 :(得分:6)
以下是我的ElementEntity代码的快照:
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private List<ElementEntity> children;
@JoinColumn(name = "ParentId", referencedColumnName = "ElementId")
@ManyToOne(fetch = FetchType.LAZY)
private ElementEntity parent;
数据库中有哪些字段:
ElementId
- 主键; ParentId
与父母的关系答案 1 :(得分:1)
你不能 - 你需要数据库中的两个记录。
实际上,对于友谊关系,我会说像neo4j这样的图形数据库是正确的用法。在那里你有两个用户,只需添加边缘“朋友”。
答案 2 :(得分:1)
至少你需要一个relational table
。
所以你有USER
表和FRIENDS
:
user_id friend_id
1 2
但@Bozho答案比我的好(neo4j
)。
答案 3 :(得分:0)
嗯,实际上你可以。
您可以使用@PreUpdate,@ PrePersists,@ PostUpdate等注释来手动转换集合的元素。这样,您的实体可以按照您想要的方式呈现,而在数据库中,您只能存储原始文本。
更合理的替代方案是使用@Convert注释,自jpa 2.1(hibernate中的@UserType)以来可用。它告诉jpa每次在数据库中读取/保存时将字段转换为另一种类型。 对于它,你应该使用@Convert anotation,指定和AttributeConverter对象。
例如
public class Parent {
@Id
private Integer id;
@Convert(converter = FriendConverter.class)
private Set<Parent>friends;
}
转换器类如下:
@Component
public class FriendConverter implements AttributeConverter<List, String>{
@Autowired
private SomeRepository someRepository;
@Override
public String convertToDatabaseColumn(List attribute) {
StringBuilder sb = new StringBuilder();
for (Object object : attribute) {
Parent parent = (parent) object;
sb.append(parent.getId()).append(".");
}
return sb.toString();
}
@Override
public List convertToEntityAttribute(String dbData) {
String[] split = dbData.split(".");
List<Parent>friends = new ArrayList<>();
for (String string : split) {
Parent parent = someRepository.findById(Integer.valueOf(string));
friends.add(accion);
}
return friends;
}
}
这是一个虚拟实现,但它给你的想法。
作为个人评论,我建议按原样映射关系。将来它会避免你的问题。在使用枚举
时,AttributeConverter会派上用场