【问题标题】:Passing fk in json via rest call as part of DerivedIdentities作为 DerivedIdentities 的一部分,通过 rest 调用在 json 中传递 fk
【发布时间】:2020-03-19 21:10:02
【问题描述】:

我有一个 Product 实体,它有一个嵌入的密钥(id、manufacturer)。我正在通过制造商的 fk 通过 REST 调用产品实体:

{
    "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

产品:

@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;

在我的控制器中,我有以下两个功能:

    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;
    }

更新

我关注了以下Stack Overflow 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

看起来 Product 的 id 没有填充,这就是它没有被创建的原因。我尝试在以下函数中设置id,产品插入成功:

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;
}

所以现在悬而未决的问题是为什么没有填充 id ?

【问题讨论】:

    标签: java spring-data-jpa spring-data dto


    【解决方案1】:

    明显的错误是@id 注释在Product 实体中的name 属性上,而它应该在manufacturer 属性上

    【讨论】:

    • 你是对的,确实@id 应该在制造商属性之上。我改变了它,但我得到了同样的错误。不确定它是否相关..
    • 是否在Manufacturer 实体中使用@Id 注释id 属性?
    • 我修复了原始问题,但由于我的解决方案出现了另一个问题,在主帖上留下了更新
    • 留下另一个更新,我在控制器中创建的产品的 id 似乎没有初始化,这就是引发异常的原因。
    【解决方案2】:

    我原来的问题是:

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

    我通过关注this post 解决了这个问题。底线是在我的 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 时,可能是与休眠相关的bug(或此bug)。

    无论哪种方式,处理和解决这个问题的方法是将 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;
    

    这将绕过 id 的休眠验证,并允许它在之后将序列值映射到它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多