作为派生身份的一部分,通过 rest 调用将 fk 传入 json
Passing fk in json via rest call as part of DerivedIdentities
我得到了一个具有嵌入式密钥(id、制造商)的产品实体。我正在通过 REST 使用制造商的 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
产品:
@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 class :
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;
....
并且在产品 class 中,我在制造商上方添加了以下注释:
@Id
@ManyToOne(fetch=FetchType.LAZY)
@MapsId("manufacturer")
private Manufacturer manufacturer;
现在我收到以下错误:
org.hibernate.HibernateException: No part of a composite identifier may be null
更新 2
产品的 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?
明显的错误是在 Product
实体中 name
属性 上的 @id
注释,而它应该在 manufacturer
属性
我原来的问题是:
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
可能是 bug(or this bug) 使用@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;
这将绕过 id 的 hibernate 验证,并允许它随后将序列值映射到它。
我得到了一个具有嵌入式密钥(id、制造商)的产品实体。我正在通过 REST 使用制造商的 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
产品:
@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 class :
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;
....
并且在产品 class 中,我在制造商上方添加了以下注释:
@Id
@ManyToOne(fetch=FetchType.LAZY)
@MapsId("manufacturer")
private Manufacturer manufacturer;
现在我收到以下错误:
org.hibernate.HibernateException: No part of a composite identifier may be null
更新 2
产品的 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?
明显的错误是在 Product
实体中 name
属性 上的 @id
注释,而它应该在 manufacturer
属性
我原来的问题是:
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
可能是 bug(or this bug) 使用@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;
这将绕过 id 的 hibernate 验证,并允许它随后将序列值映射到它。