OneToOne-Relation с API Spring Boot Rest и JPA => попытались назначить идентификатор из нулевого свойства «один к одному» - PullRequest
0 голосов
/ 27 октября 2018

В моем собственном проекте я использую Angular 6 для разработки веб-интерфейса и Spring Boot 2 для разработки бэкэнда. Бэкэнд использует Spring Boot JPA для подключения к базе данных Postgres, также я использую Spring Boot Rest для создания API, используя конечные точки по умолчанию, созданные Spring Boot Rest. Таким образом, нет ручных услуг или контроллеров.

У меня есть Person-Entity и Address-Entity с отношением oneToOne. Все сущности расширяют BaseEntity:

@Data
@MappedSuperclass
@OptimisticLocking(type = OptimisticLockType.DIRTY)
@EntityListeners({AuditingEntityListener.class})
public class BaseEntity {
    @Id
    @GeneratedValue(generator = "uuid2", strategy = GenerationType.AUTO)
    @GenericGenerator(name = "uuid2", strategy = "uuid2")
    @Type(type = "uuid-binary")
    private UUID id;

    @CreatedDate
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;

    @CreatedBy
    private String createdBy;

    @LastModifiedDate
    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;

    @LastModifiedBy
    private String lastModifiedBy;
}

лицо

@Data
@Entity
@Table(name = "person")
public class Person extends BaseEntity {
    private String lastName;
    private String firstName;
}

Адрес

@Data
@Entity
@Table(name = "address")
public class Address extends BaseEntity {

    @OneToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL)
    @MapsId
    private Person person;

    private String street;
    private String houseNumber;
    private String zipCode;
    private String city;
    private String state;
}

Мои репозитории выглядят так:

public interface AddressRepository extends CrudRepository<Address, UUID> {
}

и

public interface PersonRepository extends CrudRepository<Person, UUID> {    
}

При публикации

{
  "street":"exStreet",
  "housenumber":"121",
  "zipcode":"14321",
  "city":"exCity",
  "state":"exState",
  "person":{
    "lastName":"ExampleLastName",
    "firstName":"ExampleFirstName"}
}

до http://localhost:8080/addresses Я всегда получаю следующую ошибку

org.springframework.orm.jpa.JpaSystemException: попытка присвоить идентификатор из нулевого однозначного свойства [Address.person];

вместе с

org.hibernate.id.IdentifierGenerationException: попытка присвоить идентификатор из нулевого однозначного свойства [Address.person]

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

frontend: angular form => service => вызов httpclient с показанным json => post to spring boot api server // работает, я думаю

backend: сервер api с весенней загрузкой, десериализация json для адреса и person-entity => address.setPerson (person) => сохранение через jpa в базу данных

Есть ли способ достичь этого с помощью какой-то настройки Джексона или чего-то в этом роде, или мне снова нужно написать службы для контроллеров, позаботиться о связывании, ...? Вот уже два дня я борюсь с этим, поэтому любая помощь очень ценится.

EDIT После дальнейшего расследования я уверен, что проблема заключается в картировании. Но я не знаю, как комментировать мои сущности или какую конфигурацию необходимо выполнить.

1 Ответ

0 голосов
/ 27 октября 2018

Хорошо, наконец-то мне удалось заставить это работать. Проблема была действительно картированием. Я реализовал пользовательский десериализатор и зарегистрировал его с помощью @JsonDeserialize (используя = AddressDeserializer.class) в Address-Entity. Смотри ниже.

@Component
public class AddressDeserializer extends StdDeserializer<Address> {

    public AddressDeserializer() {
        super(Address.class);
    }

    @Override
    public Address deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonNode addressNode = jsonParser.getCodec().readTree(jsonParser);

        Person person = new Person();
        person.setLastName(addressNode.get("person").get("lastName").textValue());
        person.setFirstName(addressNode.get("person").get("firstName").textValue());
        System.out.println("##### ----- person.getLastName: " + person.getLastName());

        Address address = new Address();
        address.setPerson(person);
        address.setStreet(addressNode.get("street").textValue());
        address.setHouseNumber(addressNode.get("housenumber").textValue());
        address.setZipCode(addressNode.get("zipcode").textValue());
        address.setCity(addressNode.get("city").textValue());
        address.setState(addressNode.get("state").textValue());

        return address;
    }
}

Адрес-Entity:

...
@JsonDeserialize(using = AddressDeserializer.class)
public class Address extends BaseEntity implements Serializable {
...

Встроенный HTTP-клиент IntelliJ IDEA: POST http://localhost:8080/addresses Тип контента: приложение / hal + json Принимаем: / Cache-Control: без кеша

{
  "street":"exStreet",
  "housenumber":"121",
  "zipcode":"14321",
  "city":"exCity",
  "state":"exState",
  "person":{
    "lastName":"ExampleLastName",
    "firstName":"ExampleFirstName"}
}

Результат с результирующим адресом:

POST http://localhost:8080/addresses

HTTP/1.1 201 
Last-Modified: Sat, 27 Oct 2018 13:50:16 GMT
Location: http://localhost:8080/addresses/89f57064-b4b4-4e1a-adae-142d8c09d834
Content-Type: application/hal+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sat, 27 Oct 2018 13:50:16 GMT

{
  "id": "89f57064-b4b4-4e1a-adae-142d8c09d834",
  "createdDate": "2018-10-27T13:50:16.803+0000",
  "createdBy": "testsystem",
  "lastModifiedDate": "2018-10-27T13:50:16.803+0000",
  "lastModifiedBy": "testsystem",
  "street": "exStreet",
  "houseNumber": "121",
  "zipCode": "14321",
  "city": "exCity",
  "state": "exState",
  "_links": {
    "self": {
      "href": "http://localhost:8080/addresses/89f57064-b4b4-4e1a-adae-142d8c09d834"
    },
    "address": {
      "href": "http://localhost:8080/addresses/89f57064-b4b4-4e1a-adae-142d8c09d834"
    },
    "person": {
      "href": "http://localhost:8080/addresses/89f57064-b4b4-4e1a-adae-142d8c09d834/person"
    }
  }
}

Response code: 201; Time: 225ms; Content length: 693 bytes

Результирующий человек:

{
  "id" : "89f57064-b4b4-4e1a-adae-142d8c09d834",
  "createdDate" : "2018-10-27T13:50:16.808+0000",
  "createdBy" : "testsystem",
  "lastModifiedDate" : "2018-10-27T13:50:16.808+0000",
  "lastModifiedBy" : "testsystem",
  "lastName" : "ExampleLastName",
  "firstName" : "ExampleFirstName",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/persons/89f57064-b4b4-4e1a-adae-142d8c09d834"
    },
    "person" : {
      "href" : "http://localhost:8080/persons/89f57064-b4b4-4e1a-adae-142d8c09d834"
    }
  }
}

База данных:

SELECT * FROM ADDRESS;
CREATED_BY      CREATED_DATE    LAST_MODIFIED_BY    LAST_MODIFIED_DATE      CITY    HOUSE_NUMBER    STATE   STREET      ZIP_CODE    PERSON_ID  
testsystem  2018-10-27 15:50:16.803 testsystem  2018-10-27 15:50:16.803 exCity  121 exState exStreet    14321   89f57064b4b44e1aadae142d8c09d834

SELECT * FROM PERSON;
ID      CREATED_BY      CREATED_DATE    LAST_MODIFIED_BY    LAST_MODIFIED_DATE      FIRST_NAME      LAST_NAME  
89f57064b4b44e1aadae142d8c09d834    testsystem  2018-10-27 15:50:16.808 testsystem  2018-10-27 15:50:16.808 ExampleFirstName    ExampleLastName

Вот и все. Спасибо за чтение.

...