【问题标题】:Spring data JPA - How to return id of the nested mapping using projection and/or named query?Spring data JPA - 如何使用投影和/或命名查询返回嵌套映射的 id?
【发布时间】:2020-11-09 20:45:11
【问题描述】:

我有这些实体 - 物品

 @Entity
 @Table(name="Item")
 public class Item 
 {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private Long id;
    
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="item_set_id")
    private ItemSet itemSet;
    
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="category_id")
    private Category category;

    @Column(name="category_name")
    private String categoryName;
    
    // 5 other fields which aren't required for the query
 }

Category -

@Entity
@Table(name="Category")
public class Category
{
    @Id
    @Column(name="id")
    private Long id;
    
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="parent_id")
    private Category parent_id;
    
    @Column(name="name")    
    private String name;
}

我需要运行这个 sql 查询:

select id, category_id, category_name from Item where item_set_id = ?

我在ItemRepository 中使用这个[1],但性能并不好。它正在检索ItemCategory 中的所有字段(包括我不需要的与Category 的连接)。

[1]

@Query("SELECT i FROM Item i WHERE item_set_id = ?1")
List<Item> findByItemSet(Long itemSetId);

我正在尝试使用命名查询和投影来提高性能,但我似乎无处可去。我不断遇到 - Validation failed for query for method public abstract java.util.List findByItemSet(Long)。我已经尝试创建一个 DTO 类和一个接口来做同样的事情,但它仍然不起作用。

@Query("SELECT a.id, "
            + "a.category_name, a.category_id FROM Item a WHERE a.item_set_id = :itemSetId")
    List<Item> findByItemSet(Long itemSetId);

关于如何解决此问题的任何想法/建议?

编辑:我使用的是 springboot 2.0.4-RELEASE、java 8 和 MS-SQL Server 2012。

【问题讨论】:

  • 我认为,当您将最后一个变体标记为本机查询时,它应该可以工作。如果没有,请发布异常的完整堆栈跟踪。
  • @JensSchauder 将其标记为本机查询后,我遇到了 - SQL 错误:0,SQLState:S1093 列名 item_set_id 无效。

标签: spring hibernate jpa spring-data-jpa spring-data


【解决方案1】:

您在 HQL 查询中错误地使用了列名,而您应该使用属性名。

您可以访问关联的属性,这是 JPA/Hibernate 的优势所在。使用

@Query("SELECT a.id, a.categoryName, a.category.id FROM Item a WHERE a.itemSet.id = :itemSetId")
List<Tuple> findByItemSet(Long itemSetId);

如果你想要实体对象,你也可以使用以下

@Query("FROM Item a LEFT JOIN FETCH a.category WHERE a.itemSet.id = :itemSetId")
List<Item> findByItemSet(Long itemSetId);

如果您想使用自定义 DTO,请使用:

@Query("SELECT new com.dto.ItemDTO(a.id, a.categoryName, a.category.id) FROM Item a WHERE a.itemSet.id = :itemSetId")
List<ItemDTO> findByItemSet(@Param("itemSetId") Long itemSetId);

【讨论】:

  • 对于第一个,我仍然遇到这个 - 上下文初始化期间遇到异常 - 取消刷新尝试:org.springframework.beans.factory.UnsatisfiedDependencyException:org.springframework.beans.factory.BeanCreationException : 创建名为“itemRepository”的 bean 时出错:调用 init 方法失败;嵌套异常是 java.lang.IllegalArgumentException: Validation failed for query for public abstract java.util.List com.itemhelperservice.data.repository.ItemRepository.findByItemSet(java.lang.Long)!
  • 如您所见,我将返回类型更改为Tuple。您不能以这种方式返回托管实体。您需要一个 DTO,然后您可以执行以下操作 SELECT NEW com.mycompany.MyDto(a.id, a.categoryName, a.category.id) FROM ...
  • 我仍然遇到同样的错误。我用了这个@Query("SELECT new com.dto.ItemDTO(a.id, a.category_name, a.category_id) FROM Item a WHERE a.item_set_id = :itemSetId") List&lt;ItemDTO&gt; findByItemSet(@Param("itemSetId") Long itemSetId);。 category_id 和 category_name 可能是null。不确定这是否会以某种方式影响它。
  • 您在 HQL 查询中错误地使用了列名,而您应该使用属性名。使用@Query("SELECT new com.dto.ItemDTO(a.id, a.categoryName, a.category.id) FROM Item a WHERE a.itemSet.id = :itemSetId") List&lt;ItemDTO&gt; findByItemSet(@Param("itemSetId") Long itemSetId);
  • 我更新了答案。嗯,有很多书可以用来学习。您也可以尝试一些教程,例如 Oracle 的官方教程:docs.oracle.com/javaee/6/tutorial/doc/bnbpz.html
猜你喜欢
  • 2022-12-02
  • 2021-01-08
  • 2020-06-23
  • 1970-01-01
  • 2018-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-19
相关资源
最近更新 更多