代码之家  ›  专栏  ›  技术社区  ›  oBit91

JPA查询实现另一个

  •  0
  • oBit91  · 技术社区  · 7 年前

    我一直在努力使用JPA将我们的系统从手动休眠转换为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()和filter,但这似乎是一种浪费。

    在搜索答案的过程中,我发现了一个存储库的以下实现,它允许我们检索所有子类。

    @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>
    

    但是,这无法解决问题,因为类型不是“Monitorbale”,而是“Linux”。它不会更改查询,只会对调用者实施更多限制。

    谢谢

    编辑:

    我知道接口不会影响表本身,否则我就会知道如何查询它。另一方面,编写一个自定义回购协议,检查类型(例如 Linux )是一个 instanceof 界面感觉真的不对。

    1 回复  |  直到 7 年前
        1
  •  0
  •   oBit91    7 年前

    这是我最终写下的有效解决方案:

    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;
    }