13
public interface UserRepository extends JpaRepository<User, Long> {

  @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?0", nativeQuery = true)
  User findByEmailAddress(String emailAddress);
}

Let's say I have the code above where I select * from user. What should I do if I don't want this method to return User object. Is there a way I can manually map the data to a custom object MyUser? Can I do all this in the UserRepository interface?

Thanks!

1
  • You are configuring Spring Security right? you don't need to extend JPARepsoitory you can use its super type and just create a repository that uses raw JDBC or whatever. With JPARepository Spring knows how to set up the JPA persistence up. If you use raw JDBC you would need to configure your bean with the db connection. If you know JPA then sure you can configure JPA to map queries into value objects or map a custom entity class hierarchy to a set of user tables, Spring is all about configuring objects and using interfaces you just implement the interfaces and have Spring wire them up. Commented Nov 13, 2015 at 21:42

2 Answers 2

17

You can do something like this

@Query(value = "SELECT YOUR Column1, ColumnN FROM USERS WHERE EMAIL_ADDRESS = ?0", nativeQuery = true)
List<Object[]> findByEmailAddress(String emailAddress);

You have to do the mapping. Take a look at the Spring Data Repository as well. Source

Sign up to request clarification or add additional context in comments.

Comments

6

What about interface based projection?

Basically you write interface with getters that correspond to SQL query parameters.

In this way you even don't need to force @Id parameter on projection:

@Entity
public class Book {
     @Id
     private Long id;
     private String title;
     private LocalDate published;
}

public interface BookReportItem {
     int getYear();
     int getMonth();
     long getCount();
}

public interface BookRepository extends Repository<Book, Long> {
     @Query(value = "select " +
                    "  year(b.published) as year," +
                    "  month(b.published) as month," +
                    "  count(b) as count," +
                    " from Book b" +
                    " group by year(b.published), month(b.published)")
     List<BookReportItem> getPerMonthReport();
}

It uses org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap underneath as proxy for interface in current Spring implementation.

It works for nativeQuery = true too.

4 Comments

Projections don't work with some frameworks like Thymeleaf collections where you need an actual object to be referenced in your HTML, i.e. Getters and Setters for form tracking.
I am facing an issue while trying to use this interface based projection approach. W.r.t this example, List<BookReportItem> returned from getPerMonthReport() gives me a List<AbstractJpaQuery$TupleConverter$TupleBackedMap> instead of the actual enriched/populated BookReportItem objects. Please suggest how can I unproxy each individual object and fetch the values. Hibernate.unproxy/initialize does not work. I don't want to go back to using native queries.
@JatinShashoo Use MapStruct or other mapping framework. Spring has only generic interface proxy implementation. It doesn't care about actual classes. You can use select new full.path.to.Constructor(args, go, here) from ... JPA/Hibernate syntax to provide actual constructor type, but not for native queries (( For native queries I use BeanPropertyRowMapper.
@Entity annotation is required for Book class of course

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.