[英]JPA repository with single table inheritance (hibernate)
我创建了两个扩展Employee
实体的实体( RegularEmployee
和ContactEntity
)。
@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.