java - JPA 检索所有引用的关系(ManyToMany - ManyToOne - OneToMany)

标签 java jpa jakarta-ee

正在开发这个“twitter”应用程序,用户可以在其中发布帖子@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 中获得以下额外的 Prop ,因此不确定这是否是一个简洁的解决方案:

"_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<>();

它仍然返回所有关注者(我想要的!)我只是不想要followers.followers和followers.posts..

最佳答案

最佳猜测:在您尝试取消引用这些对象之前,它实际上并没有获取这些对象。

默认情况下,JPA 将急切获取 @OneToOne 和 @OneToMany 关系,但不会获取 @ManyToOne 或 @ManyToMany。发生的情况是,当您引用这些字段时,它将去获取列表的实际内容。

你怎么知道这种情况正在发生?使用 getFollowers().getClass() 检查列表的类 您看到的不会是 LinkedList 或 ArrayList,而是 JPA 提供者提供的一个类,名称中可能带有“Lazy”。当您在列表上调用 Size 或 Get 时,它将执行获取。

您也可以将 OneToOne 和 OneToMany 关系设置为惰性关系,并使用 EntityGraphs 来确定您想要急切获取哪些实体。 JPA 有很多这样的陷阱。

我已经看到提到过 GSON,只是一个警告:它不会意识到延迟加载列表,所以你必须告诉它避免使用你不希望它遵循的属性。

通常使用 JSON 编码(marshal)处理时,您会希望它忽略父对象,因此在 Post 中,应忽略 User。另外,到相同类型的链接通常应该被忽略(关注者)或者专门映射,这样它就不会编码整个对象,而只生成用户名数组。您可以告诉它忽略实际的关注者字段,并让它编码一个返回用户名数组的 getter 来实现此目的。

关于java - JPA 检索所有引用的关系(ManyToMany - ManyToOne - OneToMany),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49027819/

相关文章:

java - Hibernate S1093 或 07009 参数索引无效

java - 如何使用 Java EE 7 WebSockets 实现推送到客户端?

java - Java 小程序中的碰撞检测帮助

java - 在 JPA 中保留 map

Java:如何构建可扩展的Job处理机制

java - 如何将 native 查询重写为 JPA 标准

java - 在文件中存储大量对象的最佳方法是什么?

jakarta-ee - com.sun.jersey.server.impl.application.WebApplicationImpl _handleRequest

java - 如何在 lucene 中编写正则表达式模式?

java - Apache POI 3.10。 XSFFONT 设置颜色不起作用