Reputation: 215
There is 1 table (respectively 1 entity) called Product. I want to create a Self Relation - some products are parents to others. That's because 1 product can consist of many other products. I have already created a basic relation through another entity that stores only the id of the parent and the child.
When 1 product has another product as a children I should be able to set how many of this product are needed to build the parent product. There are plenty of tutorials showing how to do this with code but I am creating a REST service so I need to create CRUD of the Product entity.
Product Entity
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String sku;
private String name;
private BigDecimal price;
@JsonProperty("special_price")
@Column(name = "special_price")
private BigDecimal specialPrice;
private BigInteger quantity;
private BigInteger booked;
private BigInteger ordered;
@ManyToMany
@JoinTable(
name = "product_children",
joinColumns = @JoinColumn(name = "parent_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "children_id", referencedColumnName = "id")
)
private Set<Product> children = new HashSet<>();
// constructors, getters and setters
Now that's the way to create new product (via post request):
{
"sku": "emil1",
"name": "Test",
"price": 10.00,
"special_price": 8.99,
"children": [{ "id": 1 }]
}
I want to be able to specify how many products of a type are needed to build the parent product. Here is the JSON that I want to send:
{
"sku": "emil1",
"name": "Test",
"price": 10.00,
"special_price": 8.99,
"children": [{ "id": 1, "quantity": 2, "required": true }]
}
Can the controller process the last JSON? If yes, how to do it? Maybe some kind of JSON deserializer? If no, what is the best way to do it?
Now I am able to get the child id in the service with @Transient
id field in the ProductChildren entity. Some code:
@Entity
@Table(name = "products_children")
public class ProductChildren implements Serializable {
@Transient
private long id;
private long quantity;
private boolean required;
@Id
@ManyToOne
@JoinColumn(name = "parent_id")
private Product parent;
@Id
@ManyToOne
@JoinColumn(name = "children_id")
private Product child;
// constructors, getters and setters
}
The Product entity:
@ManyToMany
private Set<ProductChildren> children = new HashSet<>();
When I try to start the application this error occurs:
Invocation of init method failed; nested exception is org.hibernate.MappingException: Foreign key (FKm30xghohr4mj5am5c7gqxkist:products_children [children_parent_id,children_children_id])) must have same number of columns as the referenced primary key (products_children [product_id,children_parent_id,children_children_id])
I noticed that it's trying to access fields children_parent_id,children_children_id
that aren't in the table.. But why does it put this prefix? How can I do the relation?
How to represent this tables with Spring JPA/Hibernate?
Upvotes: 0
Views: 268
Reputation: 66
Don't know if i understood your requirement correctly, but i would create a transient attribute at the product entity so SpringBoot would deserialize it normally into the RequestBody (your Product entity).
.
.
private BigInteger quantity;
private BigInteger booked;
private BigInteger ordered;
@Transient
private boolean required;
.
.
And you can treat this attribute in the controller as you wish.
Upvotes: 1