有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

具有单表继承的java JPA存储库(hibernate)

我已经创建了两个扩展RegularEmployee实体的实体(RegularEmployeeContactEntity

@Entity
@Table(name="employees")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue(value="employee")
public class Employee {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

...

Im为此实现使用了SINGLE_TABLE继承,并创建了一个用于操作数据的通用JpaRepository:

@Repository
public interface EmployeeRepository<T extends Employee> extends JpaRepository<T, Long> {
}

我还创建了一个服务类,用于自动连接这些通用存储库的三个实例,以及每个类的特定方法

@Service
public class EmployeeService {

    @Autowired
    private EmployeeRepository<Employee> employeeRepo;

    @Autowired
    private EmployeeRepository<RegularEmployee> regularRepo;

    @Autowired
    private EmployeeRepository<ContractEmployee> contractRepo;

    public List<Employee> getAllEmployee() {
        return employeeRepo.findAll();
    }

    public List<RegularEmployee> getAllRegularEmployee(){
        return regularRepo.findAll();
    }

    public List<ContractEmployee> getAllContractEmployee() {
        return contractRepo.findAll();
    }
...

我的问题是,当我试图找到所有正式员工或合同员工时,我总是得到所有类型的员工(员工、正式员工和合同员工)

我不知道为什么它会这样,即使该方法的签名说它返回适当的类型


共 (2) 个答案

  1. # 1 楼答案

    我已经能够用通用的EmployeeRepository复制您遇到的情况。作为替代方案,我创建了两个独立的存储库:ContractualEmployeeRepository和RegularEmployeeRepository

    public interface ContractualEmployeeRepository extends JpaRepository<ContractualEmployee, String> {
    }
    
    public interface RegularEmployeeRepository extends JpaRepository<RegularEmployee, String> {
    }
    

    然后,我创建了一个集成测试

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {Main.class})
    @TestExecutionListeners({DependencyInjectionTestExecutionListener.class,
            TransactionalTestExecutionListener.class,
            DbUnitTestExecutionListener.class})
    @TestPropertySource(locations="classpath:application-test.properties")
    @DatabaseSetup("classpath:SingleTableDataSet.xml")
    public class IntegrationTest {
    
        @Autowired
        private RegularEmployeeRepository regularEmployeeRepository;
    
        @Autowired
        private ContractualEmployeeRepository contractualEmployeeRepository;
    
        @Test
        public void test() {
            Assert.assertEquals(6, regularEmployeeRepository.findAll().size());
            Assert.assertEquals(4, contractualEmployeeRepository.findAll().size());
        }
    
    }
    

    它是有效的

    至于Spring数据JPA存储库中泛型的用法和限制:https://stackoverflow.com/a/19443031/14180014他在解释它时做了大量工作

  2. # 2 楼答案

    一种选择是在EmployeeRepository中使用@Query

    public interface EmployeeRepository<T extends Employee> extends JpaRepository<T, Long> {
        @Query("from RegularEmployee")
        List<RegularEmployee> findAllRegularEmployees();
    }
    

    第二个选项是为Employee的每个子类创建一个额外的存储库。对于RegularEmployee而言,将是:

    public interface RegularEmployeeRepository extends EmployeeRepository<RegularEmployee>{}
    

    这是如何在EmployeeService中使用这两个选项:

    @Service
    public class EmployeeService {
        @Autowired EmployeeRepository<Employee> employeeRepo;
    
        @Autowired EmployeeRepository<RegularEmployee> regularRepoT;
    
        @Autowired RegularEmployeeRepository regularRepo;
    
        @PostConstruct
        public void init(){
            employeeRepo.save(new ContractEmployee("Mark"));
            employeeRepo.save(new RegularEmployee("Luke"));
            employeeRepo.findAll().forEach(System.out::println); // prints Mark and Luke
            regularRepo.findAll().forEach(System.out::println); // prints only Luke
            regularRepoT.findAllRegularEmployees().forEach(System.out::println); // prints only Luke
        }
    //...
    }
    

    您还可以在EmployeeRepository之上省略@Repository。Spring已经知道这是一个存储库,因为它扩展了JpaRepository

    旁注:如果不需要Spring创建EmployeeRepository,请在其类的顶部添加@NoRepositoryBean