Сопоставление многих объектов Spring с одним во встроенном объекте - PullRequest
4 голосов
/ 01 августа 2020

Я создаю простое приложение для блога с весенней загрузкой. В этом приложении есть два объекта: пользователь и сообщение. Таблица пользователей содержит пользовательские данные и имеет первичный ключ в качестве Id, а таблица сообщений содержит информацию о содержимом с информацией о пользователе в качестве внешнего ключа postedBy, который относится к идентификатору пользовательской таблицы. Один пользователь может иметь много сообщений.

На основании этого я разработал класс Entity, как показано ниже.

введите описание изображения здесь

@Entity
@Table
public class User {
    @Id
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    private String id;
    private String name;
    private String email;
}


@Entity
@Table
public class Post {
    @Id
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    private String id;
    private String title;
    @ManyToOne
    @JoinColumn(name = "id" , insertable = false,updatable = false)
    private User postedBy;
    private String content;
}

Поскольку пользователь может иметь несколько сообщений, у меня есть аннотация пользователя @ ManyToOne , которая сопоставляется с идентификатором пользователя через @ JoinColumn

Я использую интерфейс JpaRepository, который затем открывается через контроллер отдыха.

Но когда я отправляю тело для вставки сообщения, как показано ниже

{
    "title":"The Graphql way of design",
    "postedBy":"402880ee73aa45570173aa462ea00001",
    "content":" The content of blog "
}

, появляется ошибка ниже

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.graphql.blog.model.User` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('402880ee73aa45570173aa462ea00001'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.graphql.blog.model.User` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('402880ee73aa45570173aa462ea00001')
 at [Source: (PushbackInputStream); line: 3, column: 13] (through reference chain: com.graphql.blog.model.Post["postedBy"])]

Я ожидал, что столбец postedBy будет хранить «402880ee73aa45570173aa462ea00001», поскольку пользователь уже существует, и в ответ он отправит данные пользователя, автоматически извлекая данные пользователя для этого сообщения.

Ответы [ 3 ]

2 голосов
/ 01 августа 2020

Вы получаете сообщение об ошибке, потому что строковое поле не может десериализоваться в объект User.

Я ожидал, что столбец postedBy будет хранить «402880ee73aa45570173aa462ea00001», поскольку пользователь уже существует, и в ответ, он отправит с данными пользователя, автоматически получая данные пользователя для этого сообщения.

Нет, spring не может сделать это автоматически. Чтобы сделать это, сначала правильно десериализуйте идентификатор, используя json, как это.

{
    "title":"The Graphql way of design",
    "postedBy":{
                  "id": "402880ee73aa45570173aa462ea00001"
               },
    "content":" The content of blog "
}

Затем сначала выберите User по идентификатору и установите в Post, например:

Optional<User> user = userRepository.findById(post.getPostedBy.getId());
post.setUser(user.get());

И используйте @JoinColumn для поля, в котором вы хотите сохранить внешний ключ для пользователя в таблице сообщений.

@ManyToOne
@JoinColumn(name = "postedBy")
private User postedBy;
1 голос
/ 01 августа 2020

Добавьте аннотацию @JsonIdentityInfo к классу User:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")

Аннотация, используемая для указания того, что значения аннотированного типа или свойства должны быть сериализованы, чтобы экземпляры либо содержат дополнительный идентификатор объекта (в дополнение к фактическим свойствам объекта), либо как ссылку, состоящую из идентификатора объекта, который относится к полной сериализации.

1 голос
/ 01 августа 2020

В соответствии с вашими требованиями вы должны ввести следующий код:

В классе User:

@OneToMany(mappedBy = "postedBy", cascade = CascadeType.DETACH)
private List<Post> posts;

В классе Post:

@ManyToOne
@JsonIgnore
private User postedBy;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...