我一直致力于使用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
界面是否真的错了。
答案 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;
}