春季数据JPA- Findall不返回关系数据

发布于 2025-01-23 13:46:51 字数 1475 浏览 0 评论 0 原文

我有2个桌子 - 放映(许多人)和房间(Onetomany)。当我在房间存储库上使用Findall时,它会将我的JSON返回带有屏幕数据的JSON,但是当我以相反的方式进行此操作(screenings.findall)时,它不会返回房间。在模型筛选中,我有关系:

@ManyToOne
@JoinColumn(name = "room_id")
@JsonBackReference
private Room room;

在房间模型中:

@OneToMany(mappedBy="room")
@JsonManagedReference
private List<Screening> screenings;

ScreeningService包含:

    @Autowired
    public ScreeningService(ScreeningRepository screeningRepository) {
        this.screeningRepository = screeningRepository;
    }

    public List<Screening> getScreenings(){
        return screeningRepository.findAll();
    }

返回的值没有房间模型:

{
"id": 1,
"startDate": "2022-06-20T13:00:00.000+00:00",
"endDate": "2022-06-20T15:00:00.000+00:00"
},
{
"id": 2,
"startDate": "2022-06-20T13:15:00.000+00:00",
"endDate": "2022-06-20T15:15:00.000+00:00"
},

当我以相反的方式进行操作和呼叫

public List<Room> getRooms() {
        return roomRepository.findAll();
    }

结果与我想要的完全相同:

{
"id": 2,
"number": 2,
"screenings": [
{
"id": 2,
"startDate": "2022-06-20T13:15:00.000+00:00",
"endDate": "2022-06-20T15:15:00.000+00:00"
},
{
"id": 5,
"startDate": "2022-06-20T13:15:00.000+00:00",
"endDate": "2022-06-20T15:15:00.000+00:00"
},
{
"id": 7,
"startDate": "2022-06-20T18:15:00.000+00:00",
"endDate": "2022-06-20T21:15:00.000+00:00"
}
]
},

可以做或我做错事?

I have 2 tables - Screenings (ManyToOne) and Rooms (OneToMany). When I'm using findAll on rooms repository it returns me a json with screenings data but when Im doing that in opposite way (screenings.findAll) it does not returns rooms. In model Screening I have relation:

@ManyToOne
@JoinColumn(name = "room_id")
@JsonBackReference
private Room room;

and in Room model:

@OneToMany(mappedBy="room")
@JsonManagedReference
private List<Screening> screenings;

ScreeningService contains:

    @Autowired
    public ScreeningService(ScreeningRepository screeningRepository) {
        this.screeningRepository = screeningRepository;
    }

    public List<Screening> getScreenings(){
        return screeningRepository.findAll();
    }

and returned values are without Room model:

{
"id": 1,
"startDate": "2022-06-20T13:00:00.000+00:00",
"endDate": "2022-06-20T15:00:00.000+00:00"
},
{
"id": 2,
"startDate": "2022-06-20T13:15:00.000+00:00",
"endDate": "2022-06-20T15:15:00.000+00:00"
},

When Im doing that in opposite way and call

public List<Room> getRooms() {
        return roomRepository.findAll();
    }

result is exactly same as I want:

{
"id": 2,
"number": 2,
"screenings": [
{
"id": 2,
"startDate": "2022-06-20T13:15:00.000+00:00",
"endDate": "2022-06-20T15:15:00.000+00:00"
},
{
"id": 5,
"startDate": "2022-06-20T13:15:00.000+00:00",
"endDate": "2022-06-20T15:15:00.000+00:00"
},
{
"id": 7,
"startDate": "2022-06-20T18:15:00.000+00:00",
"endDate": "2022-06-20T21:15:00.000+00:00"
}
]
},

Is that possible to make or Im doing something wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

‖放下 2025-01-30 13:46:51

问题在于JSON序列化级别。

您有双向关系!

如果您默认情况下将这些对象序列化,而无需其他注释( @jsonmanagedReference @jsonbackReference ),您将获得 StackoverFlowerRorRor exception。原因是杰克逊通过双向关系进入无限的递归。

因此,要解决Jackson Json Infinite Recursion问题,您使用了 @jsonmanagedReference @jsonbackReference 。注释的主要思想是,关系将分为两个部分:父母和孩子。

是参考的父(或“向前”)部分 - 正常序列化的一个。

是参考的儿童(或“背部”)部分 - 将从序列化中省略它。

因此,杰克逊将仅序列化一个关系部分,而永远不会进入无限循环。您可以在示例中看到它。

另外,我们还可以使用
@jsonignore 注释只是简单地忽略了关系的一个方面,从而破坏了链条。

如果您想具有从双方序列化对象的能力:

解决方案:

用于指示注释类型的值或
属性应序列化,以便实例包含
附加对象标识符(此外,实际对象属性),
或作为由对象ID组成的参考
序列化。实际上,这是通过序列化第一个来完成的
实例为完整对象和对象身份,以及其他引用
对象作为参考值。

删除 @jsonmanagedReference @jsonbackReference 您的实体注释。

将类级注释添加到筛选实体:

@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class, 
  property = "id")
public class Screening { ... }

将类级注释添加到 ROOM 实体:

@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class, 
  property = "id")
public class Room { ... }

ROOM> ROOM 实体的输出:

{
  "id": 2,
  "number": 2,
  "screenings": [
    {
      "id": 2,
      "startDate": "2022-06-20T13:15:00.000+00:00",
      "endDate": "2022-06-20T15:15:00.000+00:00",
      "room": 2
    },
    {
      "id": 5,
      "startDate": "2022-06-20T13:15:00.000+00:00",
      "endDate": "2022-06-20T15:15:00.000+00:00",
      "room": 2
    },
    {
      "id": 7,
      "startDate": "2022-06-20T18:15:00.000+00:00",
      "endDate": "2022-06-20T21:15:00.000+00:00",
      "room": 2
    }
  ]
}

筛选实体:

{
  "id": 2,
  "startDate": "2022-06-20T13:15:00.000+00:00",
  "endDate": "2022-06-20T15:15:00.000+00:00",
  "room": {
    "id": 2,
    "number": 2,
    "screenings": [2,5,7]
  }
}

如果 @jsonidentityinfo 的默认行为不适合您的用例how-do-i-us-a-a-custom-serializer-with-jackson>自定义序列化器并自己​​处理双向问题。

The problem is on JSON serialization level.

You have a bidirectional relationship!

If you will serialize these objects by default without additional annotations(@JsonManagedReference, @JsonBackReference ) you will get StackOverflowError exception. The reason is that Jackson gets into infinite recursion by the bidirectional relationship.

So to resolve Jackson JSON infinite recursion problem you used @JsonManagedReference, @JsonBackReference. The main idea of annotations is that relation will be split into two parts: parent and child.

@JsonManagedReference is the parent (or "forward") part of the reference – the one that gets serialized normally.

@JsonBackReference is the child (or "back") part of the reference – it will be omitted from serialization.

So Jackson will serialize only one relation part and never gets into the infinity loop. You can see it in your example.

Alternatively, we can also use the @JsonIgnore annotation to simply ignore one of the sides of the relationship, thus breaking the chain.

In case you want to have the ability to serialize objects from both sides:

Solution: Annotation JsonIdentityInfo

Annotation used for indicating that values of annotated type or
property should be serializing so that instances either contain
additional object identifier (in addition actual object properties),
or as a reference that consists of an object id that refers to a full
serialization. In practice this is done by serializing the first
instance as full object and object identity, and other references to
the object as reference values.

Remove @JsonManagedReference, @JsonBackReference annotations from your entities.

Add the class level annotation to Screening entity:

@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class, 
  property = "id")
public class Screening { ... }

Add the class level annotation to Room entity:

@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class, 
  property = "id")
public class Room { ... }

The output of Room entity:

{
  "id": 2,
  "number": 2,
  "screenings": [
    {
      "id": 2,
      "startDate": "2022-06-20T13:15:00.000+00:00",
      "endDate": "2022-06-20T15:15:00.000+00:00",
      "room": 2
    },
    {
      "id": 5,
      "startDate": "2022-06-20T13:15:00.000+00:00",
      "endDate": "2022-06-20T15:15:00.000+00:00",
      "room": 2
    },
    {
      "id": 7,
      "startDate": "2022-06-20T18:15:00.000+00:00",
      "endDate": "2022-06-20T21:15:00.000+00:00",
      "room": 2
    }
  ]
}

The output of Screening entity:

{
  "id": 2,
  "startDate": "2022-06-20T13:15:00.000+00:00",
  "endDate": "2022-06-20T15:15:00.000+00:00",
  "room": {
    "id": 2,
    "number": 2,
    "screenings": [2,5,7]
  }
}

In case the default behavior of @JsonIdentityInfo does not fit your use case, you can create Custom Serializer and handle bidirectional problem on your own.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文