Repository 方法只能返回整个实体而不是某些属性 [英] Repository method only works returning the whole entity instead of some properties

查看:40
本文介绍了Repository 方法只能返回整个实体而不是某些属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

<块引用>

异常堆栈跟踪

从处理程序中解决异常[公共 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,org.springframework.data.rest.webmvc.support.DefaultedPageable,org.springframework.data.domain.Sort,org.springframework.data.rest.webmvc.Persis帐篷实体资源组装器)]: java.lang.IllegalArgumentException: PersistentEntity 不能为空!

<块引用>

实体

@Entity@Table(name="reference_data")@NamedQueries({@NamedQuery(name="MyTable.findX", query = "SELECT t.name FROM MyTable t WHERE t.catId = 330 ")})公共类 MyTable 实现了 Serializable {@Id私人长ID;@Column(name="cat_id")私人长猫ID;@列(名称=名称")私人字符串名称;}

<块引用>

存储库界面

@RepositoryRestResource(collectionResourceRel = "myTables", path = "myTables")//公共接口MyTableDataRepository扩展PagingAndSortingRepository{//这没有用.公共接口 MyTableDataRepository 扩展 JpaRepository{//@Query("SELECT a.name FROM MyTable a WHERE a.catId = 330 ") -- 这不起作用.//@Query(value= "SELECT r.name FROM my_table r ", nativeQuery = true) -- 这也不起作用.@Query("SELECT DISTINCT a.name FROM MyTable a WHERE a.catId = 330 ")//这也不起作用.列表<字符串>findX();//这没有用.//列表findX();//带有一个属性的 DTO:字符串名称.. 也不起作用.}

如您所见,即使根据数千个示例,上述存储库方法都应该有效.

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

@Query("SELECT a FROM MyTable a WHERE a.catId = 330")//这有效列表findX();//这有效

<块引用>

技术栈

+-------------------------------+-----------------+|依赖 |版本 |+-------------------------------+-----------------+|spring-boot-starter-web |1.3.5.发布 ||spring-boot-starter-data-jpa |1.3.5.发布 ||spring-boot-starter-data-rest |1.3.5.发布 ||HikariCP |2.4.6 ||PostgreSQL |9.3-1102-jdbc41 ||JDK |8 |+-------------------------------+-----------------+

如果您能帮助查询仅返回选定的属性,我将不胜感激.

解决方案

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

虽然您可以创建一个 String 类包装器,它也是一个数据库实体,正如这里所建议的 这是一种糟糕的方法,完全没有必要.

实现您想要的目标的正确方法是使用投影.您将定义一个投影界面,像这样公开您想要的字段:

@Projection(name = "myTableNameProjection", types = MyTable.class)公共接口 MyTableNameProjection {字符串 getName();}

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

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

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

这里 是一个解释投影的相关问题,这里是文档的相关部分,这里 是一个示例项目.

I cannot return specific properties of an entity class from a repository method.

Exception stacktrace

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 class

@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;
}

Repository interface

@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.
}

As you can see, none of the repository methods above works even though they should according to thousands of examples.

The only way I have got it working is as follows:

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

Technical stack

+-------------------------------+-----------------+
| 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               |
+-------------------------------+-----------------+

I'd really appreciate any help in getting the query to return only selected properties to work.

解决方案

This stems from a misunderstanding of what Spring Data REST can do. Whilst you can do what you are describing through direct repository access, you are accessing this method through the automatically exposed REST endpoint, and these only work on mapped classes. This means that any repository methods you expose with Spring Data REST need to return entity types, i.e. those which are annotated with @Entity which java.lang.String is not.

Whilst you could create a String class wrapper that is also a database entity, as is suggested here this is a terrible approach, and totally unnecessary.

The proper way to achieve what you want is to use projections. You would define a projection interface exposing the fields you want like so:

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

And then, when you make the request, specify that it is the projection you are interested in.

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

The results returned will be projections only including the names of the entities. This works equally on individual requests (e.g. /mytables/1) or repository search methods.

Here is a related question explaining projections, here is the relevant section of the documentation, and here is an example project.

这篇关于Repository 方法只能返回整个实体而不是某些属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆