【问题标题】:Repository method only works returning the whole entity instead of some properties存储库方法仅适用于返回整个实体而不是某些属性
【发布时间】:2016-10-26 16:55:34
【问题描述】:

我无法从存储库方法返回实体类的特定属性。

异常堆栈跟踪

Resolving exception from handler 
[public org.springframework.http.ResponseEntity<java.lang.Object>            
org.springframework.data.rest.webmvc.RepositorySearchController.executeSearch
(
org.springframework.data.rest.webmvc.RootResourceInformation,
org.springframework.util.MultiValueMap<java.lang.String, java.lang.Object>, 
java.lang.String,

org.springframework.data.rest.webmvc.support.DefaultedPageable,
org.springframework.data.domain.Sort,org.springframework.data.rest.webmvc.Persis
tentEntityResourceAssembler
)
]
 : java.lang.IllegalArgumentException: PersistentEntity must not be null!

实体

@Entity
@Table(name="reference_data")
@NamedQueries({
  @NamedQuery(name="MyTable.findX", query = "SELECT t.name FROM MyTable t WHERE t.catId = 330 ")
})
public class MyTable implements Serializable { 
  @Id
  private Long id;

  @Column(name="cat_id")
  private Long catId;

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

存储库界面

@RepositoryRestResource(collectionResourceRel = "myTables", path = "myTables")
//public interface MyTableDataRepository extends PagingAndSortingRepository<MyTable, Long> {  // This didn't work.
public interface MyTableDataRepository extends JpaRepository<MyTable, Long> {
  //@Query("SELECT a.name FROM MyTable a WHERE a.catId = 330 ") -- This didn't work.
  //@Query(value= "SELECT r.name FROM my_table r ", nativeQuery = true) -- This didn't work either.
  @Query("SELECT DISTINCT a.name FROM MyTable a WHERE a.catId = 330 ") // This didn't work either.
  List<String> findX();  // This didn't work.

  //List<MyDTO> findX(); // DTO with one property: String name.. didn't work either.
}

如您所见,即使根据数千个示例,上述存储库方法都不起作用。

我让它工作的唯一方法如下:

@Query("SELECT a FROM MyTable a WHERE a.catId = 330") // This WORKS
List<MyTable> findX();  // This WORKS

技术栈

+-------------------------------+-----------------+
| Dependency                    | Version         |
+-------------------------------+-----------------+
| spring-boot-starter-web       | 1.3.5.RELEASE   |
| spring-boot-starter-data-jpa  | 1.3.5.RELEASE   |
| spring-boot-starter-data-rest | 1.3.5.RELEASE   |
| HikariCP                      | 2.4.6           |
| postgresql                    | 9.3-1102-jdbc41 |
| JDK                           | 8               |
+-------------------------------+-----------------+

非常感谢任何帮助,让查询仅返回选定的属性才能工作。

【问题讨论】:

  • 您遇到的是 Spring Data REST 的设计方式。它仅适用于实体。有关更多详细信息以及解决设计约束的方法,请参阅下面的@Will 答案。

标签: spring-boot spring-data-jpa spring-data-rest


【解决方案1】:

这源于对 Spring Data REST 可以做什么的误解。虽然您可以通过直接存储库访问来执行您所描述的操作,但您正在通过自动公开的 REST 端点访问此方法,并且这些仅适用于映射类。这意味着您使用 Spring Data REST 公开的任何存储库方法都需要返回实体类型,即那些用 @Entity 注释的那些 java.lang.String 不是。

虽然您可以创建一个 String 类包装器,它也是一个数据库实体,as is suggested here 这是一种糟糕的方法,完全没有必要。

实现您想要的正确方法是使用投影。您将定义一个投影接口,像这样公开您想要的字段:

@Projection(name = "myTableNameProjection", types = MyTable.class)
public interface MyTableNameProjection {
    String getName();
}

然后,当您提出请求时,指定它是您感兴趣的投影

curl 'http://localhost:8080/mytables?projection=myTableNameProjection'

返回的结果将是仅包括实体名称的投影。这同样适用于单个请求(例如/mytables/1)或存储库搜索方法。

Here 是解释预测的相关问题,here 是文档的相关部分,here 是示例项目。

【讨论】:

  • 您的解释只是部分正确。 Spring Data JPA 完全能够返回 List&lt;String&gt;List&lt;Integer&gt; 或任何等效项。但是,Spring Data REST 仅适用于数据的默认视图,即实体。您引用的文档和示例也与 Spring Data REST 相关。
  • @manish 是的,我认为问题与弹簧数据 REST 有关,因为它被标记为这样,这是我之前看到此错误的唯一情况。我将更新答案以反映这是 Spring Data REST 特定的怪癖。
  • 伙计们,我知道 SpringDataRest 仅适用于实体,但是当您想避免暴露机密信息时,这有一个缺点,否则视图数据库对象会暴露机密表字段吗?跨度>
  • @Jrr 如果您不想泄露机密字段,请用@JsonIgnore 标记它们,它们不会被序列化。或者,您可以为称为“摘录”投影的存储库定义默认实体投影,它不会公开机密字段。然后您可以在@RepositoryRestResource(excerptProjection=MyProjection.class) 中设置它
【解决方案2】:

我认为返回值不应该是List&lt;String&gt;,而是List&lt;Object[]&gt;

【讨论】:

    【解决方案3】:

    伙计们,我已经尝试了很多可能的解决方法(tkxs 用于您的输入),但是在 spring-data-rest 下,只有整个实体才能工作,否则我会得到:'cause': null message: PersistentEntity must not be空值!' .. 这需要写在某个地方.. 只是为了避免你知道的头痛。
    此外,根据 spring-data-* 文档,我们可以使用 @RestResource(exported = false) 来隐藏 HAL 中的查询方法和实体的字段.. cuNextChallenge.

    【讨论】:

      【解决方案4】:

      我遇到了同样的错误。我通过在我的服务文件中添加 @Service 注释来修复它

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-03
        • 1970-01-01
        • 1970-01-01
        • 2021-09-11
        • 2013-01-29
        相关资源
        最近更新 更多