So I have the following application, which has one entity called Product
that inherits two other entities (Product > Bike, Product > Wheel). Controllers look like this:
public abstract class ProductController<T extends Product> {
@Autowired
private ProductService<T> productService;
@PostMapping
public ResponseEntity post(@RequestBody T product) {
return ResponseEntity.ok(productService.save(product));
}
@GetMapping
public ResponseEntity get() {
return ResponseEntity.ok(productService.findAll());
}
}
@RestController
@RequestMapping("/products/categories/bikes")
public class BikeController extends ProductController<Bike> {}
@RestController
@RequestMapping("/products/categories/wheels")
public class WheelController extends ProductController<Wheel> {}
Entities:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
public Product() {}
//getters and setters
}
@Entity
public class Bike extends Product {
private String color;
public Bike() {}
//getters and setters
}
@Entity
public class Wheel extends Product {
private Double diameter;
public Wheel() {}
//getters and setters
}
Product repository:
public interface ProductRepository<T extends Product> extends CrudRepository<T, Long> {}
Product service:
@Service
public class ProductService<T extends Product> {
@Autowired
private ProductRepository<T> productRepository;
public T save(T product) {
return productRepository.save(product);
}
public Iterable<T> findAll() { return productRepository.findAll(); }
}
After running the program it creates three tables for each entity. If i call the post
method from the concrete controller it adds the entity to its table. But the findAll() method returns entities not from the concrete table but from the product table. So my question is why is this happening (even if i specified the Entity type in the repository)?
CodePudding user response:
What you want to achive is impossible because Bike
is a subtype of Product
in java but not for JPA. In the Database it usally split into different Tables for each Subtype and only the tables (seen by JPA as entites) can be queried. So a Spring Repository can't query it either, because it uses JPA internally.
Please take a look here and read more about jpa inheritance: https://www.baeldung.com/hibernate-inheritance
Generally: It is bad pratice to have different table for each Type of Product. Everytime you add a new Product you would have to add a whole new class and table in database. It is best practice to just have a single entity/class (and thus a single table) for Product
and a field to distinguish between different types of products. In it's simplest form a String productType
, but i would recommand using a seperate Entity ProductType
with an id and name (in its simplest form) and have a @OneToMany
relation between Product
and ProductType
. Additonal data like color
and diameter
could be stored using a field of type Map
with @ElementCollection
or in a another entity for (dynamic) additional data (as seen here: https://stackoverflow.com/a/15061468/7142748).