Search code examples
javaspring-bootspring-repositories

Single repository for multiple objects with @DiscriminatorValue


I have several entities sharing the same database table with @DiscriminatorValue with one base class:

@Entity(name = "base_details")
@DiscriminatorColumn(name = "type")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Getter
@Setter
public abstract class BaseDetails {

    @Id
    @Column(name = "identifier")
    private String identifier;

    @Column(name = "item_type")
    @Enumerated(EnumType.STRING)
    private Type type;

}

@Entity
@DiscriminatorValue("ONE")
@Getter
@Setter
public class FirstDetails extends BaseDetails {
...
}

@Entity
@DiscriminatorValue("TWO")
@Getter
@Setter
public class SecondDetails extends BaseDetails {
...
}

This works fine but I am running into an issue with having too many separate repositories:

@Repository
public interface OneDetailsRepository extends JpaRepository<OneDetails, String> { ... }

etc.

Is there a way how to have a single repository (eq. BaseDetailsRepository) which would work with all derived entities?

EDIT: What I am looking for is something like this:

@Repository
public interface BaseDetailsRepository extends JpaRepository<? extends BaseDetails, String> { 
    OneDetails findOne(String identifier);
    SecondDetails findOne(String identifier);
}

Solution

  • You can do as follows :

    Repository : BaseDetailsRepo.java

    @Repository
    public interface BaseDetailsRepo extends JpaRepository<BaseDetails, String>{
    //make the return according to you ..it shouldn't be list....
    
        @Query("FROM SecondDetails AS bd WHERE bd.identifier=:identifier")
        public List<SecondDetails> getSecondDetailsByIdentifier(@Param("identifier") String identifier);
    
        @Query("FROM FirstDetails AS bd WHERE bd.identifier=:identifier")
        public List<FirstDetails> getFirstDetailsByIdentifier(@Param("identifier") String identifier);          
    }
    

    Controller : DemoController.java

    @Controller
    public class DemoController {
    
        @Autowired
        private BaseDetailsRepo baseDetailsRepo;
    
    
        @GetMapping(value="/test")
        public ResponseEntity test(){
    
            FirstDetails fd = new FirstDetails();
            fd.setIdentifier("fd1-demo");
    
            FirstDetails fd1 = new FirstDetails();
            fd1.setIdentifier("fd2-demo");
    
    
            SecondDetails sd = new SecondDetails();
            sd.setIdentifier("sd1-demo");
            baseDetailsRepo.save(fd);
            baseDetailsRepo.save(fd1);
            baseDetailsRepo.save(sd);
    
            return new ResponseEntity("Success",HttpStatus.OK);
        }
    
    
        @GetMapping(value="/test/second/{id}")
        public ResponseEntity getSecondDetails(@PathVariable String id){
            return new ResponseEntity(baseDetailsRepo.getSecondDetailsByIdentifier(id),HttpStatus.OK);
        }
    
    
        @GetMapping(value="/test/first/{id}")
        public ResponseEntity getFirstDetails(@PathVariable String id){
            return new ResponseEntity(baseDetailsRepo.getFirstDetailsByIdentifier(id),HttpStatus.OK);
        }
    }
    

    Output

    Test