Kiril Stoyanov
Kiril Stoyanov

Reputation: 215

Spring Boot Entity (relation with extra columns) via RestController

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?

Update

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?

Database schema

enter image description here How to represent this tables with Spring JPA/Hibernate?

Upvotes: 0

Views: 268

Answers (1)

ricktg
ricktg

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

Related Questions