Spring Data JPA,为CrudRepository接口中的@EntityGraph参数化

5
使用Spring Data JPA,是否可以像这样做:
public interface UserDao extends CrudRepository<User, Long> {

@EntityGraph(value = :graphName, type = EntityGraph.EntityGraphType.LOAD)
    @Query(value = "SELECT DISTINCT u FROM User u")
    List<User> findAllWithDetailsByGraphName(@Param(value="graphName") String graphName);

}

能否在运行时将图形名称传递到方法中,并使用一组需要的集合调用加载操作?这种构造方式不起作用,会产生编译时错误。对此的任何尝试都失败了...
因此,我在用户类中有多个集合,我希望根据条件进行加载。
@Entity
@Table(name="user")
@NamedEntityGraphs({
        @NamedEntityGraph(name = "User.details", attributeNodes = {
                @NamedAttributeNode("phones"), @NamedAttributeNode("emails"), @NamedAttributeNode("pets")}),
        @NamedEntityGraph(name = "User.phones", attributeNodes =
                {@NamedAttributeNode("phones")}),
        @NamedEntityGraph(name = "User.emails", attributeNodes =
                {@NamedAttributeNode("emails")}),
        @NamedEntityGraph(name = "User.pets", attributeNodes =
                {@NamedAttributeNode("pets")})
})
public class User {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO, generator="native")
    @GenericGenerator(name = "native", strategy = "native")
    @Column(name="user_id")
    private Long userId;

    @Column(name="name")
    private String name;

// more fields omitted

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private Set<Phone> phones;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private Set<Email> emails;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private Set<Pet> pets;
}

现在,我只需要像这样隐式地声明所有方法:
@EntityGraph(value = "User.phones", type = EntityGraph.EntityGraphType.LOAD)
@Query(value = "SELECT DISTINCT u FROM User u")
List<User> findAllWithPhones();

感谢您的建议!

(谢谢您的建议!)

这个回答解决了你的问题吗?Spring Data JPA和NamedEntityGraphs - Réda Housni Alaoui
1个回答

7

您可以定义一个基本的JPA存储库,接受实体图作为参数。这在与规范结合使用时特别有用。因此,下面是一个基于规范的示例。还可以构造其他查询,使用不同类型的参数。

@NoRepositoryBean
public interface MyBaseRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {

    T findOne(Specification<T> spec, EntityGraphType entityGraphType, String entityGraphName);

    List<T> findAll(Specification<T> spec, Sort sort, EntityGraphType entityGraphType, String entityGraphName);

}

实现基本仓库:

@NoRepositoryBean
public class MyBaseRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements MyBaseRepository<T, ID> {

    private EntityManager em;

    public MyBaseRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.em = entityManager;
    }

    public MyBaseRepositoryImpl(Class<T> domainClass, EntityManager em) {
        super(domainClass, em);
        this.em = em;
    }

    @Override
    public T findOne(Specification<T> spec, EntityGraph.EntityGraphType entityGraphType, String entityGraphName) {
        TypedQuery<T> query = getQuery(spec, (Sort) null);
        query.setHint(entityGraphType.getKey(), em.getEntityGraph(entityGraphName));
        return query.getSingleResult();
    }

    @Override
    public List<T> findAll(Specification<T> spec, Sort sort, EntityGraph.EntityGraphType entityGraphType, String entityGraphName) {
        TypedQuery<T> query = getQuery(spec, sort);
        query.setHint(entityGraphType.getKey(), em.getEntityGraph(entityGraphName));
        return query.getResultList();
    }

}

指定自定义基础存储库:

<jpa:repositories base-package="my.domain" base-class="my.repository.MyBaseRepositoryImpl" />

继承自自定义基础存储库:

public interface UserRepository extends JpaRepository<User, Long>, MyBaseRepository<User, Long>, JpaSpecificationExecutor<User> {
}

使用自定义仓库的方法:
Specification mySpecs = ...
List<User> user = picklistRepository.findAll(mySpecs, EntityGraphType.LOAD, "User.phones");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接