Kevin Z
Kevin Z

Reputation: 41

How to write a custom @Query in Spring Data JDBC?

In Spring Data JDBC examples, how do I write a simple query in @Query annotation?

e.g. In LegoSet Repository, how do I add a simple findByName query?

When I tried

@Query("select * from lego_set where name = :name") List<LegoSet> findByName(@Param("name") String name); it throws following error:

org.springframework.data.mapping.MappingException: Could not read property @org.springframework.data.annotation.Id() @org.springframework.data.relational.core.mapping.Column(value=handbuch_id, keyColumn=)private java.lang.Long example.springdata.jdbc.basics.aggregate.Manual.id from result set!
...

> Caused by: org.hsqldb.HsqlException: Column not found: manual_handbuch_idat org.hsqldb.error.Error.error(Unknown Source) at org.hsqldb.error.Error.error(Unknown Source) `

Also, the reference document seems to be copied from some generic spring data document since it mentioned derived query which doesn't exist in spring data jdbc yet.

Upvotes: 4

Views: 18721

Answers (3)

einsA
einsA

Reputation: 931

Just as a completion of @jens-schauder's answer:

The query should be:

    @Query("SELECT ls.id, ls.name, ls.min_age, ls.max_age, " +
            "h.handbuch_id AS manual_handbuch_id, h.author AS manual_author, h.text AS manual_text " +
            "FROM lego_set ls JOIN handbuch h ON ls.id = h.handbuch_id " +
            "WHERE name = :name")
    List<LegoSet> findByName(@Param("name") String name);

Using this method the following test passes:

    @Test
    public void so_52978700() {
        // prepare
        LegoSet cars = createLegoSet("Small Car - 01", 5, 10);
        cars.setManual(new Manual("Just put all the pieces together in the right order", "Jens Schauder"));
        repository.save(cars);

        // execute
        List<LegoSet> actual = repository.findByName("Small Car - 01");

        // verify
        assertThat(actual).hasSize(1);
        assertThat(actual.get(0).getName()).isEqualTo("Small Car - 01");
        assertThat(actual.get(0).getManual().getText()).isEqualTo("Just put all the pieces together in the right order");
    }

Upvotes: 4

Abdullah Al Mamun
Abdullah Al Mamun

Reputation: 351

I think you are trying to execute a native query.So,try as below

@Query(  value = "SELECT * FROM lego_set ls where ls.name = :name",
           nativeQuery = true)
  List<LegoSet> findByName(@Param("name") String name);

This should work.

Upvotes: 0

Jens Schauder
Jens Schauder

Reputation: 81907

The LegoSet entity has a 1:1 relationship to a Manual. Spring Data JDBC selects such a construct using a join and expects the representative columns in the ResultSet.

Note that it expects the columns representing the Manual entity itself plus the one forming the back-reference to the LegoSet. Also, all column names are to be prefixed by the property name +_, i.e. manual_ in this case.

The error message actually tells you about the missing column (modulo a missing space): Column not found: manual_handbuch_id.

Alternatively, you can also provide your own RowMapper

Regarding the documentation:

You are kind of right. The documentation of (almost) all Spring Data modules includes a generic part which easily leads to confusion. There is a ticket for comming up with a better solution.

Upvotes: 1

Related Questions