Java JPA检索所有引用的关系(ManyToMany-ManyToOne-OneToMany)
在这个“twitter”应用程序中,用户可以拥有帖子Java JPA检索所有引用的关系(ManyToMany-ManyToOne-OneToMany),java,jpa,jakarta-ee,Java,Jpa,Jakarta Ee,在这个“twitter”应用程序中,用户可以拥有帖子@OneToMany,也可以拥有追随者@manytomy 在检索用户时,也会检索其所有帖子和关注者 这一切都是正确的,但它也检索每个帖子(即用户本身)和每个关注者的每个“海报”,所有帖子和关注者 我不知道如何将此限制到用户本身 用户 @Entity @Table(name = "User") @NamedQueries({ @NamedQuery(name = "User.findAll", query = "SELECT u FROM U
@OneToMany
,也可以拥有追随者@manytomy
在检索用户时,也会检索其所有帖子和关注者
这一切都是正确的,但它也检索每个帖子(即用户本身)和每个关注者的每个“海报”,所有帖子和关注者
我不知道如何将此限制到用户本身
用户
@Entity
@Table(name = "User")
@NamedQueries({
@NamedQuery(name = "User.findAll", query = "SELECT u FROM User u"),
@NamedQuery(
name = "User.auth",
query = "SELECT u FROM User u WHERE u.username = :username AND u.password = :password"
)
})
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
@Column(nullable = false)
private String password;
@ManyToMany
@OneToMany(mappedBy = "poster", cascade = CascadeType.ALL)
private List<Post> posts = new ArrayList<>();
@JoinTable(name = "Followers",
joinColumns = {
@JoinColumn(name = "USER_ID", referencedColumnName = "ID")
},
inverseJoinColumns = {
@JoinColumn(name = "FOLLOWER_ID", referencedColumnName = "ID")
}
)
private List<User> followers = new ArrayList<>();
.... constructor, getters and setters
我得到的结果vs我想要的
@Entity
@Table(name = "Post")
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String content;
@ManyToOne
private User poster;
.... constructor, getters and setters
{
"id": 1,
"username": "jim",
"posts": [
{
"id": 1,
"content": "Post 1 by jim",
"poster": {
// ^ this is the user itself (I don't need this one)
"id": 1,
"username": "jim",
"posts": [
// keeps recurse
]
}
}
],
"followers": [
{
"id": 2,
"username": "follower1",
"posts": [
{
"id": 4,
"content": "Post 2 by follower 1",
"poster": {
// ^ this is the follower itself (I don't need this one)
"id": 2,
"username": "follower1",
"posts": [
// Same issue
]
}
}
],
"followers": [], // <-- I don't need this one either
}
]
}
它可以工作,但仍然在JSONS中获得以下额外的支持,因此不确定这是否是一个最新的解决方案:
"_persistence_poster_vh": {
"sourceAttributeName": "poster",
"isInstantiated": false,
"row": {
"Post.ID": 3,
"Post.CONTENT": "Post 3 by jim",
"Post.DATETIME": "2018-01-22",
"Post.POSTER_ID": 1
},
"isCoordinatedWithProperty": false
}
及
@ManyToMany(fetch=FetchType.LAZY)
@可接合(
...
)
private List followers=new ArrayList();
仍然返回所有追随者(我想要!)我只是不想要followers.followers和followers.posts..您可以在注释中指定
fetch=FetchType.LAZY
,您不想立即获取。缺点是,如果您以后需要数据,您必须在仍然打开的会话范围内访问它。有两种方法来处理此问题-
@JsonIgnoreProperties(ignoreUnknown=true)
anotationFetchType
更改为FetchType.LAZY
,以便在准备JSON时根据需要获取所需数据,而不是一次获取所有记录最佳猜测:在您尝试取消引用这些对象之前,它实际上不会获取这些对象 默认情况下,JPA将获取@OneToOne和@OneToMany关系,但不获取@ManyToOne或@ManyToMany关系。当您引用这些字段时,它会去获取列表的实际内容 你怎么知道这是怎么回事?使用
getFollowers().getClass()
您看到的不是LinkedList或ArrayList,而是来自您的JPA提供者的类,名称中可能有“Lazy”。当您调用Size或Get进入列表时,它将执行提取
您还可以将OneToOne和OneToMany关系设置为惰性,并使用EntityGraphs来确定您想要急切获取的实体。JPA有很多这样的陷阱
我已经看到GSON提到过,只是一个警告:它不会知道延迟加载列表,所以您必须告诉它避免您不希望它遵循的属性
通常,在JSON封送处理中,您希望它忽略父对象,因此在Post中,用户应该被忽略。此外,到相同类型的链接通常应该被忽略(followers)或专门映射,这样它就不会对整个对象进行马歇尔处理,而只生成一个用户名数组。您可以告诉它忽略实际的followers字段,并让它封送一个getter,该getter返回一个用户名数组来实现这一点。请参阅上的答案Henry@JimVercoelen我可以删除第二点,但第一点仍然建议采用另一种方法来处理该案件。因此,请随意编辑答案,而不是否决投票。请参阅Henry上的答案您更新了答案。您在GSON中提到忽略它,而不是提取本身。我已经想到了这个,但是如果我不需要的话,获取所有实体及其所有关系,然后用JSON转换器忽略它们,这不是效率低下吗?确实是,但一般来说,JPA只急切地获取基数1关系,而不是每个关系的整个列表,因此,开销比您想象的要小得多。这也不是问题的根源。基本上,您遇到的问题似乎是对JPA的延迟加载语义缺乏了解,以及它如何与JSON封送等交互,而不是对实体缺乏适当的延迟加载语义。关于包含GSON详细信息的更新,您最初的问题中没有提到这一点,所以我本来没有谈过。当我注意到你正在整理实体图时,你的问题变得非常清楚。那么,我怎么会让每个User.followers.followers和User.followers.posts不断递归呢?我在记录列表类名时检查了它,它确实是一个JPA列表类型。所以问题是跟随者调用的转换器会在轮到它的时候被获取,或者?我更新了我的问题。在Post.poster上使用fetch=FetchType.LAZY即可。但是在User.followers上使用它仍然会返回followers(我需要)。我只是不想要User.followers.followers和User.followers.posts。
"_persistence_poster_vh": {
"sourceAttributeName": "poster",
"isInstantiated": false,
"row": {
"Post.ID": 3,
"Post.CONTENT": "Post 3 by jim",
"Post.DATETIME": "2018-01-22",
"Post.POSTER_ID": 1
},
"isCoordinatedWithProperty": false
}
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
...
)
private List<User> followers = new ArrayList<>();