[英]JPA all referenced relations are retrieved (ManyToMany - ManyToOne - OneToMany)
在这个“推特”应用程序上工作,用户可以在其中发布@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
我得到的结果 vs 我想要的结果
{
"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 中获得以下额外道具所以不确定这是否是一个完整的解决方案:
"_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<>();
这仍然返回所有关注者(我想要的!)我只是不想要 follower.followers 和 follower.posts ..
您可以在不想立即获取的注释中指定fetch=FetchType.LAZY
。 缺点是,如果您稍后需要数据,则必须在仍然打开的会话范围内访问它。
最佳猜测:在您尝试取消引用它们之前,它实际上并没有获取这些对象。
默认情况下,JPA 会急切获取@OneToOne 和@OneToMany 关系,但不会获取@ManyToOne 或@ManyToMany。 发生的情况是,当您引用这些字段时,它将去获取列表的实际内容。
你怎么能说这正在发生? 使用getFollowers().getClass()
检查列表的类 您看到的不是 LinkedList 或 ArrayList,而是来自 JPA 提供程序的类,名称中可能带有“Lazy”。 当您在列表上调用 Size 或 Get 时,它将执行获取。
您也可以将 OneToOne 和 OneToMany 关系设置为惰性关系,并使用 EntityGraphs 来确定您想要急切地获取哪些实体。 JPA 有很多这样的问题。
我已经看到 GSON 提到过,只是一个警告:它不会知道延迟加载列表,所以你必须告诉它避免你不希望它遵循的属性。
通常对于 JSON 封送处理,您会希望它忽略父对象,因此在 Post 中,例如应该忽略 User。 此外,指向相同类型的链接通常应该被忽略(关注者)或特殊映射,这样它就不会编组整个对象,而只会生成一组用户名。 您可以告诉它忽略实际的关注者字段,并让它编组一个返回用户名数组的 getter 来实现这一点。
有两种方法可以解决这个问题——
您可以在序列化对象时对要跳过的属性使用@JsonIgnoreProperties(ignoreUnknown=true)
注释。
或者您将FetchType
更改为FetchType.LAZY
以便您可以在准备 JSON 时根据需要获取所需数据,而不是一次获取所有记录。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.