使用此“推特”应用,用户可以在其中发布帖子@OneToMany
并且可以拥有关注者@ManyToMany
。
在检索用户时,所有帖子和关注者也会被检索。
这一切都是正确的,但它也检索每个帖子(用户本身)的每个“海报”以及每个关注者,所有帖子和关注者。
我无法弄清楚如何将此限制为用户自己。
用户
@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
发表
@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
}
]
}
很明显,获取一个用户填充会继续获取所有递归的关系。
这是设计师的错还是可以忽略/限制?
注意:我正在使用Gson将对象序列化为JSON格式
更新
试图使用:
@ManyToOne(fetch = FetchType.LAZY)
private User poster;
哪个有效,但仍然在JSON中得到以下额外支柱,不确定这是否是一个neath解决方案:
"_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<>();
仍然会返回所有关注者(我想要的!)我只是不想追随者。追随者和追随者。帖子..
答案 0 :(得分:1)
您可以在不想立即获取的注释中指定fetch=FetchType.LAZY
。缺点是,如果您以后需要数据,则必须在仍然打开的会话范围内访问它。
答案 1 :(得分:1)
最佳猜测:在您尝试取消引用它们之前,它实际上并未获取这些对象。
默认情况下,JPA会急切地获取@OneToOne和@OneToMany关系,但不是@ManyToOne或@ManyToMany。会发生的是,当您引用这些字段时,它将转到并获取列表的实际内容。
你怎么知道这种情况发生了?使用getFollowers().getClass()
检查列表的类
你看到的不是LinkedList或ArrayList,而是来自你的JPA提供者的类,可能在名称的某处有“Lazy”。当您在列表上调用Size或Get时,它将执行提取。
您也可以将OneToOne和OneToMany关系设置为惰性,并使用EntityGraphs确定您想要获取的实体。 JPA有很多类似的问题。
我看过GSON提到了,只是一个警告:它不会知道延迟加载列表,所以你必须告诉它以避免你不希望它遵循的属性。
通常使用JSON编组,您将希望它忽略父对象,因此在Post中,应该忽略User。此外,通常应忽略相同类型的链接(跟随者)或者特别映射,以便它不会对整个对象进行Marshall,而只生成一个用户名数组。您可以告诉它忽略实际的关注者字段,并让它编组一个getter,它返回一组用户名来实现它。
答案 2 :(得分:-1)
有两种方法可以解决这个问题 -
您可以在序列化对象时对要跳过的属性使用@JsonIgnoreProperties(ignoreUnknown=true)
anotation。
或者您将FetchType
更改为FetchType.LAZY
,以便在准备JSON时可以根据需要获取所需数据,而不是一次性获取所有记录。