JPA查询实现另一个的类

时间:2018-04-04 06:55:08

标签: java spring spring-boot jpa

我一直致力于使用JPA将我们的系统从手动hibernate转换为spring。 到目前为止,它一直很好。在某些时候,我遇到了查询实现另一个类的类的所有实例的需要。 让我们看看以下设计:

基类:机器

@Entity
@Table(name = "MACHINE")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue(value = "Machine")
public abstract class Machine implements Resource {
   // ...
}

界面:可监控

public interface Monitorable {
   // ...
}

子类:Linux

@Entity
@DiscriminatorValue("Linux")
public class Linux extends Machine implements Monitorable {
    // ...
}

使用Hibernate看起来像这样:

public static List<Machine> GetALL(Class<?> T) {
    // .. hibernate session stuff ..
    result = session.createCriteria(T).setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY).list();
    // .. closing session and error handling.
}

我有一个可用的机器存储库,我可以轻松使用findAll()然后过滤,但这似乎是浪费。

在搜索答案时,我发现了以下存储库实现,它可以让我们检索所有子类。

@NoRepositoryBean
public interface BaseMachineRepo<EntityType extends Machine> extends CrudRepository<EntityType, Long> {

    @Query("select e from #{#entityName} e")
    List<EntityType> findAllByType();
}

但是,我不太清楚如何更改此实现以适用于接口而不是类。

我最接近的是更改签名:

public interface BaseMachineRepo<EntityType extends Machine & Monitorable> extends CrudRepository<EntityType, Long>

然而,这不会解决问题,因为类型不是&#39; Monitorbale&#39;但是&#39; Linux&#39;。它不会更改查询,只会对调用者强制执行更多限制。

感谢。

编辑:

我知道界面不会影响表本身,否则我会知道如何查询它。另一方面,编写一个自定义repo来检查类型(例如Linux)是否为instanceof界面是否真的错了。

1 个答案:

答案 0 :(得分:0)

这是我最后编写的工作解决方案:

public class MachineRepoImpl implements MachineRepoCustom {

@Autowired
private MachineRepo machineRepo;

@Autowired
private ApplicationContext applicationContext;

@Override
public List<Machine> findMonitorables() {
    List<Machine> machines = machineRepo.findAll();
    Map<String, Monitorable> beansOfType = applicationContext.getBeansOfType(Monitorable.class);
    Collection<Monitorable> monitorables = beansOfType.values();
    Set<Class<? extends Monitorable>> set = new HashSet<>(); 
    List<Machine> result = new ArrayList<Machine>();

    // parses monitorable classes
    for(Monitorable m : monitorables)
    {
        set.add(m.getClass());
    }

    // checks whether the entry in the table is monitorable 
    for (Machine machine : machines) {
        if (set.contains(machine.getClass())) {
            result.add(machine);
        }
    }
    return result;
}