Repository method only works returning the whole entity instead of some properties

笑着哭i 提交于 2019-12-11 01:06:58

问题


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.


回答1:


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.




回答2:


I think the return value should not be List<String> but List<Object[]>.




回答3:


folks, I have tried with a lot of possible work-arounds (tkxs for your inputs), but under spring-data-rest just the whole entity works otherwise I get: 'cause": null message: PersistentEntity must not be null!' .. this needs to be written in some place.. just to avoid a headache you know.
Also, according to spring-data-* documentation we can use @RestResource(exported = false) to hide query methods and entities' fields in HAL.. cuNextChallenge.



来源:https://stackoverflow.com/questions/38007162/repository-method-only-works-returning-the-whole-entity-instead-of-some-properti

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!