Внешний ключ не работает на результат POST, но GET работает - PullRequest
0 голосов
/ 11 июня 2018

У меня проблема с работой с внешними ключами в Spring.Возвращенный объект не имеет правильного значения на моем корабле отношений.

orderTypeId из Order отсутствует в ответе CREATED, но последующий запрос GET дает ожидаемый результат.

Ожидаемое поведение

Вот небольшой пример того, чего я хочу достичь.

Запрос

POST /api/orders
{
    "orderType": "orderTypes/1",
}

или GET /api/orders/2

Выход

{
    "id": 2,
    "orderTypeId": 1,            // either this
    "orderType": "orderTypes/1"  // or this
    "_links": {
        "self": {
            "href": "http://localhost:8090/api/orders/2"
        },
        "order": {
            "href": "http://localhost:8090/api/orders/2"
        },
        "orderType": {
            "href": "http://localhost:8090/api/orders/2/orderType"
        },
        "orderType": {
            "href": "orderTypes/1" // this could even be acceptable
        }
    }
}

Мой код

Entites

@Data
@Entity
public class Order {
  @Id
  @GeneratedValue
  private Long id;

  @Column(name = "order_type_id", nullable = false, insertable = false, updatable = false)
  private Long orderTypeId;

  @NotNull
  @ManyToOne
  @JoinColumn(name = "order_type_id")
  private OrderType orderType;
}

@Data
@Entity
public class OrderType {
  @Id
  @GeneratedValue
  private Long id;

  @Column(nullable = false)
  private String name;

  @JsonIgnore
  @OneToMany(mappedBy = "orderType")
  private List<Order> orders;
}

Контроллер

@RepositoryRestResource
public interface OrderRepository extends JpaRepository<Order, Long> {}

POST

POST /api/orders
{
    "orderType": "orderTypes/1",
}

Выход

{
    "id": 2,
    "orderTypeId": null,
    "_links": {
        "self": {
            "href": "http://localhost:8090/api/orders/2"
        },
        "order": {
            "href": "http://localhost:8090/api/orders/2"
        },
        "orderType": {
            "href": "http://localhost:8090/api/orders/2/orderType"
        }
    }
}

Однако, если я сделаю GET /orders/2 orderTypeIdправильно установлен.

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


ОБНОВЛЕНИЕ

Я пытался что-то еще

@Data
@Entity
public class Order {
  @Id
  @GeneratedValue
  private Long id;

  @NotNull
  @ManyToOne
  @JoinColumn
  @JsonManagedReference
  @RestResource(exported=false) // ADDED
  private OrderType orderType;
}

@Data
@Entity
public class OrderType {
  @Id
  @GeneratedValue
  private Long id;

  @Column(nullable = false)
  private String name;

  // removed orders
}

GET /api / orders / 2

{
    "id": 2,
    "orderTypeId": {
        "id": 1,
        "name": "foo"
    },
    "_links": {
        "self": {
            "href": "http://localhost:8090/api/orders/2"
        },
        "order": {
            "href": "http://localhost:8090/api/orders/2"
        }
    }
}

Но теперь POST не работает: (

POST /api/orders
{
    "orderType": "orderTypes/1",
}

Возвращает 400 неверных запросов ...

Ответы [ 2 ]

0 голосов
/ 12 июня 2018

Проблема заключается в том, что это поле не будет заполнено при создании нового экземпляра, то есть в результате запроса POST.Однако он будет заполнен в ответ на запрос GET, т. Е. Он будет заполнен Hibernate в результате аннотаций JPA на поле.

Я не совсем уверен, почему вам нужно отобразить это как постоянныйполе.Простое добавление геттера должно означать, что оно включено в любой ответ JSON:

@Data
@Entity
public class Order {
  @Id
  @GeneratedValue
  private Long id;

  @NotNull
  @ManyToOne
  @JoinColumn(name = "order_type_id")
  private OrderType orderType;

  public Long getOrderTypeId(){
    return orderType != null ? orderType.getId() : null;
  }
}

Если вы не можете добавить прослушиватель для AfterCreateEvent

https://docs.spring.io/spring-data/rest/docs/current/reference/html/#events

и либо установите значение вручную для этого прослушивателя на основе связанного OrderType, либо введите EntityManager вашему слушателю и запустите обновление для сохраненного экземпляра:

https://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#refresh(java.lang.Object)

@RepositoryEventHandler 
public class OrderEventHandler {

@PersistenceContext
private EntityManager em;

  @HandleAfterCreate
  public void onOrderCreated(Order o) {
    em.refresh(o);
  }
}
0 голосов
/ 11 июня 2018

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

@Data
@Entity
public class Order {
    @Id
    @GeneratedValue
    private Long id;

   @Column(name = "order_type_id", nullable = false, insertable = false, updatable = false)
   private Long orderTypeId;

   @JsonBackReference(value="name")
   @ManyToOne
   @JoinColumn(name = "order_type_id")
   private OrderType orderType;
}


@Data
@Entity
public class OrderType {
   @Id
   @GeneratedValue
   private Long id;

   @Column(nullable = false)
   private String name;

   @JsonManagedReference(value = "name")
   @OneToMany(mappedBy = "orderType")
   private List<Order> orders;
}

Теперь, чтобы ответить на ваш вопрос, возврат post API не вернет OrderType, так как Hibernate не распознает его как инициализированную сущность.Вы можете либо выполнить вызов GET позже, как это уже происходит в вашем случае, либо иметь контроллер rest в API POST после сохранения, вы можете выполнить вызов get по id перед возвратом или использовать DTO для отправки ответа.

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