繁体   English   中英

JPA 单表存储库 inheritance(休眠)

[英]JPA repository with single table inheritance (hibernate)

我创建了两个扩展Employee实体的实体( 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;

...

我为此实现使用SINGLE_TABLE inheritance,并创建了一个通用的 JpaRepository 来处理数据:

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

我还创建了服务 class,它自动装配这些通用存储库的三个实例,以及每个 class 的特定方法。

@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();
    }
...

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

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

一种选择是在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 ,请在其 class 之上添加@NoRepositoryBean

我已经能够使用您的通用 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存储库中Generics的用法和限制: https://stackoverflow.com/a/19443031/14180014他已经做了很好的解释。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM