Home > OS >  Spring findAll() method in CrudRepository doesn't return derived entities
Spring findAll() method in CrudRepository doesn't return derived entities

Time:06-25

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).

  • Related