Передача fk в json через вызов rest как часть DerivedIdentities - PullRequest
1 голос
/ 20 марта 2020

Краткая сводка: я получил сущность Product со встроенным ключом (id, производитель). Я прохожу через остальное, вызываю сущность продукта с помощью fk производителя:

{
    "name":"Chocolate",
    "register_date":"19/03/2020",
    "manufacturer_id": 52,
    "rating":"Amazing"
}

Когда я пытаюсь сохранить сущность в контроллере, я получаю следующую ошибку

java.lang.IllegalArgumentException: Can not set com.dao.Manufacturer field com.dao.ProductId.manufacturer to java.lang.Long

Product:

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@IdClass(ProductId.class)
@Entity
public class Product {

    @Id
    @SequenceGenerator(name = "product_id_seq", sequenceName = "product_id_seq", initialValue = 1)
    @GeneratedValue(strategy=GenerationType.SEQUENCE,generator = "product_id_seq")
    private Long id;

    @ManyToOne(fetch=FetchType.LAZY)
    @Id
    private Manufacturer manufacturer;

    private String name;

    @JsonFormat(pattern = "dd/MM/YYYY")
    private Date register_date;


    @Enumerated(EnumType.ORDINAL)
    private Rating rating;

    public enum Rating {
        Amazing,Good_Value_For_Money,Bad
    }

Класс Id:

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@AllArgsConstructor
@NoArgsConstructor
public class ProductId implements Serializable {

    private Long id;
    private Manufacturer manufacturer;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ProductId pId1 = (ProductId) o;
        if (id != pId1.id) return false;
        return manufacturer.getId() == pId1.manufacturer.getId();
    }

    @Override
    public int hashCode() {
        return id.hashCode()+manufacturer.getId().hashCode();
    }
}

Я также создал объект DTO, который будет передаваться через API в контроллер:

@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor

public class ProductCreationDTO {


    private String name;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/mm/yyyy")
    private Date register_date;
    private Long manufacturer_id;
    private Product.Rating rating;

}

Производитель:

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Manufacturer {

    @Id
    @SequenceGenerator(name = "manufacturer_id_seq", sequenceName = "manufacturer_id_seq", initialValue = 1)
    @GeneratedValue(strategy=GenerationType.SEQUENCE,generator = "manufacturer_id_seq")
    private Long id;
    private String name;
    private String country;
    @OneToMany(mappedBy = "manufacturer",fetch = FetchType.LAZY)
    private List<Product> products;

В моем контроллере у меня есть следующие 2 функции:

    RestController
    @RequestMapping("/api")
    public class ProductController {

        @Autowired
        ProductService productService;

        @Autowired
        ManufacturerService manufacturerService;


        @RequestMapping(value = "/product/", method = RequestMethod.POST)
        public HttpStatus insertProduct(@RequestBody ProductCreationDTO pcd) {
            Product p = mapProductCreationDTOtoProduct(pcd);
            if(p.getManufacturer() == null)
                return HttpStatus.BAD_REQUEST;
            return productService.addProduct(p) ? HttpStatus.CREATED : HttpStatus.BAD_REQUEST;
        }

        private Product mapProductCreationDTOtoProduct(ProductCreationDTO pcd)
        {
            Product p = new Product();
            p.setName(pcd.getName());
            p.setRating(pcd.getRating());
            p.setRegister_date(pcd.getRegister_date());
            Optional<Manufacturer> m = manufacturerService.getManufacturer(pcd.getManufacturer_id());
            if (m.isPresent())
                p.setManufacturer(m.get());
            return p;
        }

the add method under the productService : 

    @Transactional
    public boolean addProduct(Product p)
    {
        return productRepository.save(p)!=null;
    }

Обновление: Я выполнил следующее stackoverflow post Я изменил ProductId на:

public class ProductId implements Serializable {

    private Long id;
    private Long manufacturer;
....

и в классе Product я добавил следующую аннотацию над производителем:

@Id
@ManyToOne(fetch=FetchType.LAZY)
@MapsId("manufacturer")
private Manufacturer manufacturer;

, и теперь я получаю следующую ошибку:

org.hibernate.HibernateException: No part of a composite identifier may be null

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

private Product mapProductCreationDTOtoProduct(ProductCreationDTO pcd)
{
    Product p = new Product();
    p.setName(pcd.getName());
    p.setRating(pcd.getRating());
    p.setRegister_date(pcd.getRegister_date());
    Optional<Manufacturer> m = manufacturerService.getManufacturer(pcd.getManufacturer());
    if (m.isPresent())
        p.setManufacturer(m.get());
    p.setId((long) 1);   <-------------------------------------------
    return p;
}

Итак, открытый вопрос: почему идентификатор не заполняется?

Ответы [ 2 ]

1 голос
/ 21 марта 2020

Моя первоначальная проблема была:

java.lang.IllegalArgumentException: Can not set com.dao.Manufacturer field com.dao.ProductId.manufacturer to java.lang.Long

Я решил ее, выполнив этот пост . Суть в том, что внутри моего IdClass тип составного объекта должен быть его PK:

public class ProductId implements Serializable {

    private Long id; // matches name of @Id attribute
    private Long manufacturer; // name should match to @Id attribute and type of Manufacturer PK

Хотя после его решения я столкнулся с новым:

org.hibernate.HibernateException: No part of a composite identifier may be null

может быть ошибка (или эта ошибка ), связанная с гибернацией при использовании @ Idclass.

В любом случае, способ решения этой проблемы и ее решения заключается в инициировании столбца id для значение:

public class Product {

    @Id
    @SequenceGenerator(name = "product_id_seq", sequenceName = "product_id_seq")
    @GeneratedValue(strategy= GenerationType.SEQUENCE,generator = "product_id_seq")
    private Long id=-1L;

Это будет обходить проверку идентификатора в спящем режиме и позволит впоследствии сопоставить значение последовательности с ним.

1 голос
/ 20 марта 2020

Очевидной ошибкой является аннотация @id над свойством name в сущности Product, тогда как она должна быть над свойством manufacturer

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