JPA Query works only native - spring-boot

Here is my repository:
public interface MachineRepository extends JpaRepository<Machine, Integer> {
#Query(value="select m.name FROM Machine m", nativeQuery = true)
Set<SomeName> getAllMachineTypes();
}
Interface:
public interface SomeName {
String getName();
}
Model:
#Data
#Entity
#Table(name="Machine")
public class Machine {
#Id
#Column(name = "id")
#GeneratedValue
private Integer id;
#Column(name = "name")
private String name;
}
Service:
#Service
public class MachineService {
#Autowired
MachineRepository machineRepository;
public Set<SomeName> getAllMachines(){
return machineRepository.getAllMachines();
}
Controller:
#Autowired
MachineService machineService;
#RequestMapping("/")
public String findMachines(){
Set<SomeName> machines = machineService.getAllMachines();
for (SomeName mch: machines
) {
System.out.println(mch.getName());
}
//...
}
When I run as it is, it prints the name to the console. But when I change nativeQuery to false (or remove it because it is false by default):
public interface MachineRepository extends JpaRepository<Machine, Integer> {
#Query(value="select m.name FROM Machine m", nativeQuery = false)
Set<SomeName> getAllMachineTypes();
}
Then I don't get any output.
Since I don't want to use nativeQuery, I would like to ask how to make it work without it.

Use this:
public interface MachineRepository extends JpaRepository<Machine, Integer> {
#Query(value="select m.name FROM Machine m")
List<String> getAllMachineTypes();
}
because m.name is a String.

Related

How to write embedded class query for filtering

I want to filter motherName and sisterName but I don't know how to write a filter for embedded class. Please help me to solve this issue. Thank you in advance!
Family1 class
#Entity
public class Family1 {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
private int id;
#Embedded
private FamilyNames familyNames;
#Column(nullable=false,name="familyMemebers")
private int familyMembers;
#Column(nullable=false,name="contactNo")
private long contactNo;
#Embedded
#Column(nullable=false, name="Address" )
private Address address;
public Family1() {}
// getters,setters
FamilyNames class
#Embeddable
public class FamilyNames {
private String yourName;
private String fatherName;
private String motherName;
private String sisterName;
public FamilyNames() {}
//getters, setters
Family1Controller class
#RestController
#RequestMapping(value = "/family1")
public class Family1Controller {
#Autowired
private Family1Service family1Service;
#RequestMapping(method=RequestMethod.GET,value="/fam1")
public List<Family1> listOfDetails(#RequestParam("keyword") String keyWord){
return family1Service.listOfDetails(keyWord);
}
}
Family1Service class
#Service
public class Family1Service {
#Autowired
private Family1Repository familyRepository;
public List<Family1> listOfDetails(String keyWord) {
return familyRepository.findAll();
}
}
Family1Repository class:
#Repository
public interface Family1Repository extends JpaRepository<Family1,Integer> {
#Query("Select f from family1 f where f.familyNames.motherName LIKE %?1%"
+ "OR f.familyNames.sisterName %?1%")
List<Family1> findAll(String keyWord);
}
please help me which way to filter particular name in embedded class using query annotation
Try to use the following query:
#Query(
"select f from Family1 f where f.familyNames.motherName LIKE '%' || :name || '%'"
+" OR f.familyNames.sisterName LIKE '%' || :name || '%'")
List<Family1> findAll(#Param("name") String keyWord);

Get records for last 3 days via Spring JPA Repository

I have an entity which contains field date.
#Entity
#Table(name="messages", schema = "users")
...
public class Message {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "author")
private String author;
#Column(name = "tags")
private String tags;
#Column(name = "message_date")
private LocalDate date;
#Override
public String toString() {
...
}
}
#Repository
public interface MessageRepository extends JpaRepository<Message, Long> {
Message findByMessageId(Long id);
}
I'm using Spring Data JPA with repository. I want to get all messages from database for last 3 days (field date). How can I do it with Spring JPA?
#Query(...?)
List<Message> findBy...?
I suggest to split the logic from the actual queries. A service could handle all the intermediate things, e.g.:
#Service
public class MessageService {
private final MessageRepository repository;
#Autowired
public MessageService(MessageRepository repository) {
this.repository = repository;
}
List<Message> getLastThreeDays() {
// subtract 3 days from today
LocalDate threeDaysAgoDate = LocalDate.now().minusDays(3);
return this.repository.findAllWithDateAfter(threeDaysAgoDate);
}
}
and your repository stays nice and clean:
#Repository
public interface MessageRepository extends JpaRepository<Message, Long> {
Optional<Message> findByMessageId(Long id);
#Query("select m from Message m where date >= :threeDaysAgoDate")
List<Message> findAllWithDateAfter(#Param("threeDaysAgoDate") LocalDate threeDaysAgoDate);
}

Hibernate: How to display data from multiple table

I am new in spring/hibernate technologies, I have tried to find an information about it, but failed, so if you can help I will be so thankful!
I need to display a JSON response in browser of multiple tables, one of the table has primary key for another one.
My entities:
#Entity
#Table
#ToString
public class Book {
#Id
#GeneratedValue(strategy = AUTO)
#JsonView(Views.IdName.class)
private Long book_id;
#JsonView(Views.IdName.class)
private String name;
#Column(length = 1000000)
private String text;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="author_id")
#JsonView(Views.IdName.class)
private Author author;
// ....get/set methods
Another one:
#Entity
#Table
#ToString
public class Page {
#Id
#GeneratedValue(strategy = AUTO)
private Long id;
#Column(length = 1000000)
private String text;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "book_id")
private Book book;
// ...get/set methods
My controllers:
#RestController
#RequestMapping("books")
public class BookController {
private final BookRepo bookRepo;
#Autowired
public BookController(BookRepo bookRepo) {
this.bookRepo = bookRepo;
}
#GetMapping
#JsonView(Views.IdName.class)
public List<Book> getAll() {
return bookRepo.findAll();
}
#GetMapping("{id}")
public Book getOne(#PathVariable("id") Book book) {
return book;
}
}
Another one:
#RestController
#RequestMapping("authors")
public class AuthorController {
private final AuthorRepo authorRepo;
#Autowired
public AuthorController(AuthorRepo authorRepo) {
this.authorRepo = authorRepo;
}
#GetMapping
public List<Author> getAll() {
return authorRepo.findAll();
}
#GetMapping("{id}")
public Optional<Author> getOne(#PathVariable("id") Long id) {
return authorRepo.findById(id);
}
}
And also repo for interaction with DB (they are the similar):
public interface AuthorRepo extends JpaRepository<Author, Long> {
}
So when I make a request for get all books, I take the following JSON:
enter image description here
Bit I want different result, something like:
[
{
"book_id" : 1,
"name": "name 1 book",
"author" :
{
"author_id" : 1,
"name": "some_name"
}
}
]
Also, when I tried to make a request for /authors/1, I will get the following response (something like recursion) :
enter image description here
So any help how can I handle with it? Thank you!
You can use a #NoRepositoryBean
like in this example:
#NoRepositoryBean
public interface MappedTypeRepository<T extends AbstractMappedType>
extends Repository<T, Long> {
#Query("select new com.example.YourObjectWithConstructor(e.attribute, sub.sub_attribute) from entity e inner join e.subtable sub where e.attribute = ?1")
List<YourObjectWithConstructor> findAllByAttribute(String attribute);
}
My example may not be 100% correct, I did not check the syntax. Feel free to explore it
Check this also:
JPQL Create new Object In Select Statement - avoid or embrace?

How to combine two DAOs in generic way with only one method in Service layer in Spring Boot

Is it possible to combine two DAOs into one Service method?
I want to create a generic method which will choose correct DAO based on the input parameter. What for now I came up with is the method which will accept Dao from the outside the service object. But this requires to initialize appropriate Dao in the Controller which is a little bit ugly...
Measurement is just an interface for Temperature.java and Humidity.java entities with separate tables on PostgreSQL.
#Service
public class MeasurementService {
#Autowired
private TemperatureDao temperatureDao;
#Autowired
private HumidityDao humidityDao;
public<T extends PagingAndSortingRepository<Measurement, Long>> void insertMeasurementForUser(String username, List<Measurement> measurements, T dao) {
dao.saveAll(measurements);
}
}
TemperatureDao.java
#Repository
public interface TemperatureDao extends PagingAndSortingRepository<Temperature, Long> {
#Query("select u from Temperature u where u.owner = ?1 order by u.id desc")
List<Temperature> findLatestTemperatureForUser(User user, Pageable pageable);
}
HumidityDao.java
#Repository
public interface HumidityDao extends PagingAndSortingRepository<Humidity, Long> {
#Query("select u from Humidity u where u.owner = ?1 order by u.id desc")
List<Humidity> findLatestHumidityForUser(User user, Pageable pageable);
}
Temperature.java
#Entity
#Table(name = "temperature")
public class Temperature implements Measurement {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#Column(name = "th1value")
private Float th1Value;
#Column(name = "timestamp")
#NotNull
private LocalDateTime timestamp;
#ManyToOne
#JoinColumn(name = "user_id")
#NotNull
private User owner;
public Temperature() {
}
public Temperature(Float th1Value, LocalDateTime timestamp, User owner) {
this.th1Value = th1Value;
this.timestamp = timestamp;
this.owner = owner;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#JsonDeserialize(using = LocalDateTimeDeserializer.class)
public LocalDateTime getTimestamp() {
return timestamp;
}
#JsonSerialize(using = LocalDateTimeSerializer.class)
public void setTimestamp(LocalDateTime timestamp) {
this.timestamp = timestamp;
}
#Override
public User getOwner() {
return owner;
}
#Override
public void setOwner(User owner) {
this.owner = owner;
}
}
Humidity.java
#Entity
#Table(name = "humidity")
public class Humidity {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#Column(name = "hum1value")
private Float hum1Value;
#Column(name = "timestamp")
#NotNull
private LocalDateTime timestamp;
#ManyToOne
#JoinColumn(name = "user_id")
#NotNull
private User owner;
public Humidity() {
}
public Humidity(Float hum1Value, LocalDateTime timestamp, User owner) {
this.hum1Value = hum1Value;
this.timestamp = timestamp;
this.owner = owner;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#JsonDeserialize(using = LocalDateTimeDeserializer.class)
public LocalDateTime getTimestamp() {
return timestamp;
}
#JsonSerialize(using = LocalDateTimeSerializer.class)
public void setTimestamp(LocalDateTime timestamp) {
this.timestamp = timestamp;
}
public User getOwner() {
return owner;
}
public void setOwner(User owner) {
this.owner = owner;
}
}
Any ideas?
You could write a Resolver pattern to return needed dao based on your conditions. You service will use the resolver to get the correct dao.
public HellDao implements BaseDao {
public void save();
}
public ByeDao implements BaseDao {
public void save();
}
public DaoResolver {
#Autowired
private helloDao;
#Autowired
private byeDao;
public BaseDao resolve(Object input) {
//based on input return the correct dao
BaseDao resolvedDao = null;
switch(input.enum) {
case Hello:
resolvedDao = helloDao;
break;
case Hello:
resolvedDao = byeDao;
break;
default:
//decide something for default
}
return resolvedDao;
}
}
public class MyService {
#Autowired
private DaoResolver daoResolver;
public Object doSomething() {
BaseDao dao = daoResolver.resolve(someObject);
//you will get HelloDao or ByeDao based on the input
dao.save();
}
}
You can check for the type of measurements using instanceof so you could do it without generics.
public void insertMeasurementForUser(String username, List<Measurement> measurements) {
if(measurements.get(0) instanceof Temperature)
temperatureDao.saveAll(measurements);
else if(measurements.get(0) instanceof Humidity)
humidityDao.saveAll(measurements);
}

How to count records with where clause in jpa test with latest spring-boot?

I have UserRepository:
public interface UserRepository extends JpaRepository<User, String> {}
The entity:
#Entity
#Table(schema="test", name = "TBL_USERS")
#Builder
#AllArgsConstructor
public class User implements Persistable<String> {
#Id
#Column(name = "ID", columnDefinition = "char")
private String id;
#NotNull
#Column(name = "NAME", columnDefinition = "char", nullable = false)
private String name;
...
}
And in my test I want to count records with certain name like the query:
select count(*) from TBL_USERS where name='John';
#Test
public void testCountSimilarNames() {
...
userRepository.count() ... ?
}
I use latest spring-boot.
You need something like :
public interface UserRepository extends CrudRepository<User , String >{
Integer countByName(String name);
}

Resources