Как создать новый объект с ассоциацией - PullRequest
0 голосов
/ 18 мая 2018

Допустим, у меня есть форма на внешнем интерфейсе с обычными полями и выпадающими списками.В этих выпадающих меню пользователь может выбрать параметр , и каждый параметр связан с сущностью в данных Spring JPA;

раскрывающиеся списки содержатнекоторая метка и ссылка на соответствующую сущность как значение .Затем это значение передается в POST-запросе в PagingAndSorting репозиторий объекта, который мы хотим создать.

Допустим, это пользователь с именем пользователя, и он должен быть связанным с одним из офисов (также юридическим лицом):

@Data
@Builder
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name="users")
public class User{

@Id
@Coluemn(name="USER_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;

@Column(name="USER_NAME", nullable=false)
private String userName;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="OFFICE_ID", **nullable=false**)
private Office office;
}

Моим первым предположением будет: Отправка POST -запроса на http://localhost:8080/api/users/ contentType: 'application / json'

{"userName":"Anton","office":"http://localhost:8080/api/offices/1"}

Но возникает исключение

{
"cause": {
    "cause": null,
    "message": "Cannot construct instance of `test.domain.Office` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/api/offices/1')\n at [Source: (org.apache.catalina.connector.CoyoteInputStream); line: 1, column: 160] (through reference chain: test.domain.User[\"office\"])"
},
"message": "JSON parse error: Cannot construct instance of `test.domain.Office` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/api/offices/1'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `test.domain.Office` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/api/office/1')\n at [Source: (org.apache.catalina.connector.CoyoteInputStream); line: 1, column: 160] (through reference chain: test.domain.User[\"office\"])"
}

Что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Оказывается, это потому, что я использовал Lombok, который сгенерировал свой собственный конструктор.Чтобы заставить его работать, мне просто нужно было установить @AllArgsConstructor следующим образом:

@AllArgsConstructor(suppressConstructorProperties = true)

Теперь все работает так, как я ожидал:

Json для отправки на http://localhost:8080/api/users:

{ "userName":"Anton", "office":"http://localhost:8080/api/offices/1" }

Что возвращает:

{ "userName":"Anton", "_links": { "self": { "href": "http://localhost:8080/api/users/28" }, "user": { "href": "http://localhost:8080/api/users/28" }, "office": { "href": "http://localhost:8080/api/users/28/office" } } }

0 голосов
/ 18 мая 2018

Вы отправляете ресурс URL в виде строки вместо объекта JSON и ожидаете, что между Спрингом и Джексоном произойдет какое-то волшебство для поиска значения.Естественно, это не то, что происходит, и Джексон пытается привязать строковое значение URL к полю Office.Конечно, это не получается, потому что он не знает, как создать объект Office из строки.

Возможное решение - провести различие между объектами Entity (теми, которые представляют таблицы вашей базы данных) и DTO (Transfer Data).Объекты), которые в этом случае представляют ваш контракт с вашим клиентом.При этом вы можете получить пользовательский объект, например, такой:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User{

  private Long userId;

  private String userName;

  private Long officeId;

}

Теперь вы можете просто отправить идентификатор офиса вместо URL, а в вашем коде использовать хранилище данных Spring для поиска объекта офиса.После этого вы можете создать свой объект Entity User, подобный показанному выше, и сохранить его.

...