Я использую версию Spring Boot 3.2 с базой данных MySQL. У меня есть два объекта
@Getter
@Setter
@Entity
@Table(name = "shops")
public class Shop{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String address;
@OneToMany(mappedBy = "shop", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Book> books;
}
и
@Getter
@Setter
@Entity
@Table(name = "books")
public class Book{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String description;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "shop_id")
private Shop shop;
}
Итак, у меня возникла проблема с ошибками, когда я пытаюсь получить все магазины со всеми книгами. У меня есть объект «Магазин со всеми объектами книг» внутри каждой книги, внутри которого есть свой собственный объект магазина со всей книгой и т. д. И это выглядит так:
[
{
"id": 4,
"address": "Street",
"books": [
{
"id": 3,
"description": "Book1",
"shop" : {
"id": 4,
"address": "Street"
"books": [
{
"id": 3,
"description": "Book1",
"shop" : { ...
}
]
}
]
}
]
Итак, проблема в том, что я хочу использовать один класс для сохранения магазинов/книг и получения данных из базы данных. Затем мне нужно, чтобы в этом магазине все книги были объектами со всеми данными, но книги имели только shopId. Итак, получение всех магазинов должно выглядеть так
[
{
"id": 4,
"address": "Street",
"books": [
{
"id": 3,
"description": "Book1",
"shop" : 4
}
]
}
]
и получение всех книг должно выглядеть так
[
{
"id": 3,
"description": "Book1",
"shop": 4
},
{
"id": 4,
"description": "Book2",
"shop": 5
},
{
"id": 5,
"description": "Book4",
"shop": 5
},
]
Как я уже сказал, я хочу использовать один и тот же класс для сохранения магазинов/книг и тот же класс для их получения. Я столкнулся с парой проблем.
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "shop_id")
private Shop shop;
на
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "shop_id")
private Long shop;
или вообще удалите @ManyToOne.
Для пункта 1 «объекты для получения, потому что если это будет 1 миллион книг, то мне нужно создать 1 миллион объектов» это произойдет в любом случае, если у вас есть 1 миллион книг, вызов книг создаст 1 миллион объектов (в списке). Для 2 «Я не могу добавить еще одну переменную, например Long shopId»; да, можешь, просто добавь комментарий @Transient
@JimGarrison Я думаю, это правильно: один экземпляр (физическая книга) книги может быть только в одном магазине?
ОП, это может тебе помочь: baeldung.com/…
Из кода было неясно, означает ли «книга» название книги или физическую книгу. Вы будете тратить много места на хранение одного и того же заголовка снова и снова. Название книги должно быть сохранено один раз вместе с его метаданными (ISBN и т. д.), а экземпляры книг должны ссылаться на эту таблицу.
@JorgeCampos да. я получаю все объекты 1M, но если я преобразую Book в BookDTO только для того, чтобы показать shop_Id вместо магазина, я получу 2M объектов вместо 1M. Имеет ли это смысл? Я могу добавить частный временный Long shopId; но в чем смысл?) Он не сериализуется, и я не получаю shopId, пока получаю все книги
@JimGarrison, на самом деле это не имеет значения. В моем проекте есть уникальные книги, и они не могут быть представлены в разных магазинах, поэтому мне подходит «Один ко многим».
Извините, это не имеет смысла, и нет, вы не будете дублировать объекты. Это либо 1 миллион для книг, либо 1 миллион для bookdto. Я не уверен, что заставляет вас думать, что это удвоит количество объектов.
@JorgeCampos Я только что узнал, что есть решение получить все данные из базы данных в виде класса Shop, а затем преобразовать их в класс ShopDTO, но во время преобразования я получаю только то, что мне нужно показать в JSON.
@Entity
@Table(name = "shops")
public class Shop {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String address;
}
@Entity
@Table(name = "books")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String description;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "shop_id")
private Shop shop;
}
SELECT s.id, s.address, b.id AS bookId
FROM shops s
LEFT JOIN books b ON s.id = b.shop_id;
А в Магазине вообще нет информации о Книгах?
Итак, я нашел решение. Я добавил @JsonIdentityInfo в свой магазин.
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Shop{...
и добавил то же самое для книги и добавил еще одну аннотацию в свой магазин.
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Book{...
@JsonIdentityReference(alwaysAsId = true)
private Shop shop;
}
Рад, что статья, которой я поделился, оказалась полезной. :)
Разве книги и магазины не связаны между собой многие-ко-многим (в реальном мире)?