是否可以编写一个Service
,提供一种方法,通过父字段选择实体,但返回一个由子类传入的子类参数(或方法的通用)?
假设Parent
有一个名为flag的字符串字段和两个孩子Child1
和Child2
,ParentService
应该可以这样使用:
Child1 child1 = parentService.findFlag(Child1.class, "de");
Child2 child2 = parentService.findFlag(Child2.class, "de");
或
Child1 child1 = parentService.findFlag<Child1>("de");
Child2 child2 = parentService.findFlag<Child2>("de");
详细示例:
因为很难解释,所以这段代码应该解释上面的场景:
Java类:
Parameter
- 具有所有孩子的公共字段的抽象父类
UiParameter
扩展参数BatchParameter
扩展参数ParameterService
- 提供save(Parameter)
方法,可用于UiParameter
和BatchParameter
此方法被其他服务用于保存各种类型的儿童现在向find(UiParameter.class, commonFieldSelector)
添加find(BatchParameter.class, commonFieldSelector)
或ParameterService
方法会很方便。
目前有4个锅炉类(UiParameterService,UiParameterRepository,BatchParameterService,BatchParameterRepository),只有1个方法看起来几乎相似。
@Data
@EqualsAndHashCode(callSuper = true)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("PARAMETER")
public abstract class Parameter extends AbstractEntity
{
// all children will share that
@ManyToOne
private Application commonField;
}
@Data
@Entity
@EqualsAndHashCode(callSuper = true)
public class UiParameter extends Parameter
{
private String foo;
}
@Data
@Entity
@EqualsAndHashCode(callSuper = true)
public class BatchParameter extends Parameter
{
private int size;
}
public interface ParameterRepository extends JpaRepository<Parameter, Long>
{
// That works great, but it returns all kind of children...
List<Parameter> findByCommonField(final Application commonField);
}
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ParameterService
{
private final ParameterRepository parameterRepository;
public ... findByCommonField...(...)
{
return ... magic ...;
}
}
对于所有Childs方法,通常的服务/存储库在我们的例子中导致只有findFlag
方法的样板类从Child1复制到ChildN。
更改域(继承策略)将是一个问题。
Spring-Solution基于Maciejs回答:
public interface ParameterRepository extends JpaRepository<Parameter, Long>
{
@Query("SELECT e FROM Parameter e WHERE TYPE(e) = ?1 AND e.commonField = ?2")
<E extends Parameter> List<E> findByTopic(final Class<E> e, final Application commonField);
}
答案 0 :(得分:2)
JPQL中有TYPE
运算符,您可以按如下方式使用它:
SELECT e
FROM EntityClass
WHERE TYPE(e) = EntityClassSubclass
您可以使用此查询,然后编写将结果转换为所需类型的通用方法。
即
private static <T extends SuperClass> List<T> queryForClass(Class<T> myClass) {
Query q = em.createQuery("SELECT p FROM SuperClass p WHERE TYPE(p) = :myClass");
q.setParameter("myClass", myClass);
List<? extends SuperClass> resultList = q.getResultList();
return (List<T>) resultList;
}