i need to update tow columns inside my table (Job this table is joint with two other tables employees and job-history)one of them is the primary key, but i get error, if someone can help.
package com.touati.org.model;
import java.io.Serializable;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.List;
/**
* The persistent class for the jobs database table.
*
*/
#Entity
#Table(name="jobs")
#NamedQuery(name="Job.findAll", query="SELECT j FROM Job j")
public class Job implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="JOB_ID")
private String jobId;
#Column(name="JOB_TITLE")
private String jobTitle;
#Column(name="MAX_SALARY")
private BigDecimal maxSalary;
#Column(name="MIN_SALARY")
private BigDecimal minSalary;
//bi-directional many-to-one association to Employee
#OneToMany(mappedBy="job")
private List<Employee> employees;
//bi-directional many-to-one association to JobHistory
#OneToMany(mappedBy="job")
private List<JobHistory> jobHistories;
public Job() {
}
public String getJobId() {
return this.jobId;
}
public void setJobId(String jobId) {
this.jobId = jobId;
}
public String getJobTitle() {
return this.jobTitle;
}
public void setJobTitle(String jobTitle) {
this.jobTitle = jobTitle;
}
public BigDecimal getMaxSalary() {
return this.maxSalary;
}
public void setMaxSalary(BigDecimal maxSalary) {
this.maxSalary = maxSalary;
}
public BigDecimal getMinSalary() {
return this.minSalary;
}
public void setMinSalary(BigDecimal minSalary) {
this.minSalary = minSalary;
}
public List<Employee> getEmployees() {
return this.employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
public Employee addEmployee(Employee employee) {
getEmployees().add(employee);
employee.setJob(this);
return employee;
}
public Employee removeEmployee(Employee employee) {
getEmployees().remove(employee);
employee.setJob(null);
return employee;
}
public List<JobHistory> getJobHistories() {
return this.jobHistories;
}
public void setJobHistories(List<JobHistory> jobHistories) {
this.jobHistories = jobHistories;
}
public JobHistory addJobHistory(JobHistory jobHistory) {
getJobHistories().add(jobHistory);
jobHistory.setJob(this);
return jobHistory;
}
public JobHistory removeJobHistory(JobHistory jobHistory) {
getJobHistories().remove(jobHistory);
jobHistory.setJob(null);
return jobHistory;
}
}
my controller: here when i try to look for all job in the data base it works fine, also if i try to update juste the title of the job it works fine to but in case that i try to set a new primary key for the job table it gives me error here my controller.
package com.touati.org.model;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
#Controller // This means that this class is a Controller
#RequestMapping(path="/project") // This means URL's start with /demo (after Application path)
public class MainController {
#GetMapping(path="/job")
public #ResponseBody Iterable<Job> getAllJob() {
// This returns a JSON or XML with the users
return jobRepository.findAll();
}
#GetMapping(path="/job/{jobId}")
public #ResponseBody String getJob(#PathVariable String jobId) {
Job job = jobRepository.findOne(jobId);
try {
job.setJobTitle("manager");
job.setJobId("test1");
jobRepository.save(job);
}
catch (Exception ex) {
return "Error updating the job: " + ex.toString();
}
return "Job succesfully updated!";
}
}
i got this error,
Error updating the user: org.springframework.orm.jpa.JpaSystemException: identifier of an instance of com.touati.org.model.Job was altered from test to test1; nested exception is org.hibernate.HibernateException: identifier of an instance of com.touati.org.model.Job was altered from test to test1
Thank you for your help.
Primary key should never be changed. If you need to change primary key it means your design is bad. If you need to change JOB_ID often then create another column for your primary key like ID. Another possibility is to copy all attributes and create new record with new JOB_ID and then remove old one.
Related
I have REST api, and when client call POST request with body, backend after deserialize should distinguish null from the absence of a value.
Because if value in JSON is null, then value in DB should become null.
If value in JSON absence, then value in DB should remain unchanged.
JSON:
{
"id" : 1,
"name" : "sample name",
"value" : null
}
OR
{
"id" : 1,
"name" : "sample name"
}
For Java after deserialization it is look like : value = null;
Java:
#Entity
#Table("sample")
public class Sample {
#Id
#Column
private Long id;
#Column
private String name;
#Column
private Integer value;
// getters / setters
}
Sample REST request:
#PutMapping
public ResponseEntity<SampleDto> updateSample(#RequestBody SampleDto dto) {
return ResponseEntity.ok(service.updateSample(dto));
}
Sample service impl:
public SampleDto updateSample(SampleDto dto) {
Sample sample = sampleRepository.findById(dto.getId);
sample.setName(dto.getName());
sample.setValue(dto.getValue());
//In this operation back need understand: value is null or absence
//Because if value in JSON is null, then value in DB should become null
//If value in JSON absence, then value in DB should remain unchanged
Sample newSample = sampleRepository.save(sample);
return modelMapper.map(newSample, SampleDto.class);
}
Project use Spring Data.
Maybe I should use #JsonDeserialize annotation or other Hibernate annotation
I tried use #JsonDeserialize, but it is not solution.
Partial update is different from full-resource update and we should implement it in a different way. Let's create two request POJO classes. One class will be used to create and update resources, second will be used to partially update given resource. To emphasise it we will use different HTTP methods. To distinguish null from absence we can use java.util.Optional class.
SampleCompleteRequest class we use together with POST (create) and PUT (update) methods.
SamplePartialRequest class we use together with PATCH (partially update) method.
To avoid boilerplate code in this example I'm using Lombok and MapStruct but it is not required.
Model
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
#Data
public class SampleCompleteRequest {
#NotBlank
private String name;
private String value;
}
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.util.Optional;
#Data
public class SamplePartialRequest {
private Optional<#NotBlank String> name;
private Optional<String> value;
}
import lombok.Data;
#Data
public class SampleResponse {
private Long id;
private String name;
private String value;
}
import lombok.Data;
#Data
public class Sample {
//#Id - Hibernate annotations are removed
private Long id;
private String name;
private String value;
}
MapStruct
In MapStruct we need to define an interface with all methods we need.
import com.example.demo.model.SampleCompleteRequest;
import com.example.demo.model.SamplePartialRequest;
import com.example.demo.model.SampleResponse;
import jakarta.annotation.Nullable;
import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.ReportingPolicy;
import java.util.Optional;
import static org.mapstruct.MappingConstants.ComponentModel.SPRING;
import static org.mapstruct.NullValueCheckStrategy.ALWAYS;
import static org.mapstruct.NullValuePropertyMappingStrategy.IGNORE;
#Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = SPRING)
public interface SamplesMapper {
#BeanMapping(nullValueCheckStrategy = ALWAYS, nullValuePropertyMappingStrategy = IGNORE)
Sample patch(SamplePartialRequest input, #MappingTarget Sample target);
Sample update(SampleCompleteRequest input, #MappingTarget Sample target);
SampleResponse mapToResponse(Sample input);
default String optionalToString(#Nullable Optional<String> nullable) {
return nullable == null ? null : nullable.orElse(null);
}
}
Plugin will generate boilerplate code for us. Below class is autogenerated and we do not need to implement it manually.
#Component
public class SamplesMapperImpl implements SamplesMapper {
#Override
public Sample patch(SamplePartialRequest input, Sample target) {
if ( input == null ) {
return target;
}
if ( input.getName() != null ) {
target.setName( optionalToString( input.getName() ) );
}
if ( input.getValue() != null ) {
target.setValue( optionalToString( input.getValue() ) );
}
return target;
}
#Override
public Sample update(SampleCompleteRequest input, Sample target) {
if ( input == null ) {
return target;
}
target.setName( input.getName() );
target.setValue( input.getValue() );
return target;
}
#Override
public SampleResponse mapToResponse(Sample input) {
if ( input == null ) {
return null;
}
SampleResponse sampleResponse = new SampleResponse();
sampleResponse.setId( input.getId() );
sampleResponse.setName( input.getName() );
sampleResponse.setValue( input.getValue() );
return sampleResponse;
}
}
Resource
A controller class is easy to implement:
import com.example.demo.model.SampleCompleteRequest;
import com.example.demo.model.SamplePartialRequest;
import com.example.demo.model.SampleResponse;
import com.example.service.SamplesMapper;
import com.example.service.SamplesService;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#AllArgsConstructor
#RestController
#RequestMapping(value = "/api/v1/samples")
public class SamplesResource {
private final SamplesMapper mapper;
private final SamplesService samplesService;
#GetMapping
public CollectionModel<SampleResponse> listAll() {
List<SampleResponse> entities = samplesService.list().stream().map(mapper::mapToResponse).toList();
return CollectionModel.of(entities);
}
#PostMapping
public EntityModel<SampleResponse> addSample(#Valid #RequestBody SampleCompleteRequest request) {
var entity = samplesService.create(request);
var response = mapper.mapToResponse(entity);
return EntityModel.of(response);
}
#PutMapping(path = "{id}")
public EntityModel<SampleResponse> updateSample(#PathVariable Long id, #Valid #RequestBody SampleCompleteRequest request) {
var entity = samplesService.update(id, request);
var response = mapper.mapToResponse(entity);
return EntityModel.of(response);
}
#PatchMapping(path = "{id}")
public EntityModel<SampleResponse> partiallyUpdateSample(#PathVariable Long id, #Valid #RequestBody SamplePartialRequest request) {
var entity = samplesService.patch(id, request);
var response = mapper.mapToResponse(entity);
return EntityModel.of(response);
}
}
A service class is also straightforward:
import com.example.demo.model.SampleCompleteRequest;
import com.example.demo.model.SamplePartialRequest;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
#AllArgsConstructor
public class SamplesService {
private final SamplesMapper mapper;
private final SamplesRepository repository;
public List<Sample> list() {
return repository.listAll();
}
public Sample create(SampleCompleteRequest request) {
var sample = mapper.update(request, new Sample());
return repository.save(sample);
}
public Sample update(Long id, SampleCompleteRequest request) {
var sample = repository.find(id).orElseThrow();
mapper.update(request, sample);
return repository.save(sample);
}
public Sample patch(Long id, SamplePartialRequest request) {
var sample = repository.find(id).orElseThrow();
mapper.patch(request, sample);
return repository.save(sample);
}
}
See also:
HTTP PUT vs HTTP PATCH in a REST API
Difference between Jackson objectMapper to others
Spring MVC PATCH method: partial updates
I'm using spring and MySQL as database to ORM. Im trying to display entity properties in grid in one of my Views. Item Id is passed by Url, and Items are set after constructor. In this scenario I'm trying to display audits that given enterprise had in the past. When navigating to given view, exception is beeing thrown:
There was an exception while trying to navigate to 'EnterpriseView/151' with the root cause 'java.lang.IllegalArgumentException: Multiple columns for the same property: auditId
What does it mean, as when I'm checking columns in database there in only one auditId in audit Table?
There are my classes:
import com.sun.istack.NotNull;
import javax.persistence.*;
#Entity
#Table
public class Audit {
private int auditId;
private Trip trip;
private User user;
private Enterprise enterprise;
public Audit() {
}
public Audit(Enterprise enterprise) {
this.enterprise = enterprise;
}
#Id
#GeneratedValue
#NotNull
#Column(unique = true)
public int getAuditId() {
return auditId;
}
#ManyToOne
#JoinColumn(name = "TRIPS_ID")
public Trip getTrip() {
return trip;
}
#ManyToOne
#JoinColumn(name = "USER_ID")
public User getUser() {
return user;
}
#ManyToOne
#JoinColumn(name = "ENTERPRISE_ID")
public Enterprise getEnterprise() {
return enterprise;
}
public void setAuditId(int auditId) {
this.auditId = auditId;
}
public void setTrip(Trip trip) {
this.trip = trip;
}
public void setUser(User user) {
this.user = user;
}
public void setEnterprise(Enterprise enterprise) {
this.enterprise = enterprise;
}
}
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.*;
import com.wtd.assistant.frontend.dao.AuditDao;
import com.wtd.assistant.frontend.dao.EnterpriseDao;
import com.wtd.assistant.frontend.domain.Audit;
import com.wtd.assistant.frontend.domain.Enterprise;
import java.util.List;
import java.util.Optional;
#Route("EnterpriseView")
public class EnterpriseView extends VerticalLayout implements HasUrlParameter<String>, AfterNavigationObserver{
private EnterpriseDao enterpriseDao;
private AuditDao auditDao;
private Grid<Audit> grid;
private List<Audit> auditsList;
private Optional<Enterprise> enterprise;
private String enterpriseId;
public EnterpriseView(EnterpriseDao enterpriseDao, AuditDao auditDao) {
this.enterpriseDao = enterpriseDao;
this.auditDao = auditDao;
this.grid = new Grid<>(Audit.class);
VerticalLayout layout = new VerticalLayout();
layout.add(grid);
grid.addColumns( "auditId" );
}
#Override
public void setParameter(BeforeEvent event, String parameter) {
enterpriseId = parameter;
System.out.println("setParameter(), enterpriseId: " + enterpriseId);
}
#Override
public void afterNavigation(AfterNavigationEvent event) {
enterprise = enterpriseDao.findById(Integer.valueOf(enterpriseId));
System.out.println("EnterpriseId: " + enterprise.get().getEnterpriseId());
auditsList = enterprise.get().getAudits();
grid.setItems(auditsList);
}
}
I tried renaming auditId property but obviously that didn't bring any result
Kind regards
Kiemoon
In the constructor of the EnterpriseView you have this code:
grid.addColumns( "auditId" );
Thats where your duplicate is comming from
enter image description hereI am new to Spring Boot Data JPA repository. This is my first application with JPA. I am trying to get data from DB. But which returns NULL.
Entity File
import javax.persistence.*;
#Entity
#Table(name = "TASK_DETAILS")
public class TaskDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TASK_DETAILS_ID")
private long taskDetailsId;
#Column(name = "TASK_NAME")
private String TaskName;
#Column(name = "TASK_POLLING_TIME")
private int TaskTime;
#Column(name = "TASK_FILE")
private String TaskClassFile;
#Column(name = "TASK_STATUS")
private String TaskStatus;
public long getTaskDetailsId() {
return taskDetailsId;
}
public void setTaskDetailsId(long taskDetailsId) {
this.taskDetailsId = taskDetailsId;
}
public String getTaskName() {
return TaskName;
}
public void setTaskName(String taskName) {
TaskName = taskName;
}
public int getTaskTime() {
return TaskTime;
}
public void setTaskTime(int taskTime) {
TaskTime = taskTime;
}
public String getTaskClassFile() {
return TaskClassFile;
}
public void setTaskClassFile(String taskClassFile) {
TaskClassFile = taskClassFile;
}
public String getTaskStatus() {
return TaskStatus;
}
public void setTaskStatus(String taskStatus) {
TaskStatus = taskStatus;
}
}
Repository File
import java.util.Collection;
import java.util.List;
import java.util.Optional;
#Repository
public interface TaskDetailsRepository extends JpaRepository<TaskDetails, String> {
TaskDetails findByTaskDetailsId(final long id);
}
My Main Method
#Service
public class ImportAmazonData {
#Autowired
private TaskDetailsRepository taskDetailsRepositoryDAO;
public void getProductsFromAmazonStore(JobExecutionContext context) throws ClassNotFoundException {
final long taskID = (long) context.getJobDetail().getJobDataMap().get("taskId");
TaskDetails taskDetails = taskDetailsRepositoryDAO.findByTaskDetailsId(taskID);
System.out.println("Result : " + taskDetails.getTaskClassFile());
}
}
ProductSync File
import com.example.Schedular.AmazonSync.ImportAmazonData;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Component;
public class ProductSync implements Job {
#Autowired
private ImportAmazonData importAmazonData;
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
try {
importAmazonData.getProductsFromAmazonStore(context);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Here i am trying to get the TaskDetails by id. But my taskDetailsRepositoryDAO was null. Here i have attached my error log. Please let me know. Thanks in advance.
ERROR LOG
java.lang.NullPointerException: null
at com.example.Schedular.AmazonSync.ImportAmazonData.getProductsFromAmazonStore(ImportAmazonData.java:20) ~[classes/:na]
at com.example.Schedular.SyncData.ProductSync.execute(ProductSync.java:16) ~[classes/:na]
at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.3.2.jar:na]
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [quartz-2.3.2.jar:na]
In your repository file i.e TaskDetailsRepository should be as below :
import java.util.Collection;
import java.util.List;
import java.util.Optional;
#Repository
public interface TaskDetailsRepository extends JpaRepository<TaskDetails, Long> {
Optional<TaskDetails> findByTaskDetailsId(Long id);
}
Use wrappers instead of primitives in your domain classes.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TASK_DETAILS_ID")
private Long taskDetailsId;
If your are trying to find a record on basis of a particular value then specify that type i.e. Long.
And always use Optional if your method is going to return a sing record from database. this will help you resovle NullPointers.
This might help you.
Try adding this in your spring boot main file(I think it is SchedularApplication)
#EnableJpaRepositories("your jpa repository package name")
I am new to Spring boot. I am trying to create the below service. Parent class is Artists. Child is Album. I am trying to fetch all the Albums corresponding to particular Artists. While creating custom method in crudRepository I am getting error. Can't able to identify the exact issue, help for the error will be greatly appreciated.
Artists.java (Bean class of Parent)
package com.org.Music_App.Artists;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
import com.org.Music_App.Albums.Album;
#Entity
public class Artists {
#Id
private int artists_Id;
private String artists_Name;
private int no_of_Albums;
private String debut_Album;
#OneToMany
#JoinColumn(name = "artists_id")
#Transient
private List<Album> album;
public Artists() {
}
public Artists(int artists_Id, String artists_Name, int no_of_Albums, String debut_Album) {
this.artists_Id = artists_Id;
this.artists_Name = artists_Name;
this.no_of_Albums = no_of_Albums;
this.debut_Album = debut_Album;
}
public int getArtists_Id() {
return artists_Id;
}
public void setArtists_Id(int artists_Id) {
this.artists_Id = artists_Id;
}
public String getArtists_Name() {
return artists_Name;
}
public void setArtists_Name(String artists_Name) {
this.artists_Name = artists_Name;
}
public int getNo_of_Albums() {
return no_of_Albums;
}
public void setNo_of_Albums(int no_of_Albums) {
this.no_of_Albums = no_of_Albums;
}
public String getDebut_Album() {
return debut_Album;
}
public void setDebut_Album(String debut_Album) {
this.debut_Album = debut_Album;
}
public List<Album> getAlbum() {
return album;
}
public void setAlbum(List<Album> album) {
this.album = album;
}
}
Album.java (Bean class of Child)
package com.org.Music_App.Albums;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Transient;
import com.org.Music_App.Artists.Artists;
#Entity
public class Album {
#Id
private int album_Id;
private int artists_Id;
private String album_Name;
private int no_of_Songs;
private String artists_Name;
public Album()
{
}
public Album(int album_Id, int artists_Id, String album_Name, int no_of_Songs, String artists_Name) {
super();
this.album_Id = album_Id;
this.artists_Id = artists_Id;
this.album_Name = album_Name;
this.no_of_Songs = no_of_Songs;
this.artists_Name = artists_Name;
}
public int getAlbum_Id() {
return album_Id;
}
public void setAlbum_Id(int album_Id) {
this.album_Id = album_Id;
}
public int getArtists_Id() {
return artists_Id;
}
public void setArtists_Id(int artists_Id) {
this.artists_Id = artists_Id;
}
public String getAlbum_Name() {
return album_Name;
}
public void setAlbum_Name(String album_Name) {
this.album_Name = album_Name;
}
public int getNo_of_Songs() {
return no_of_Songs;
}
public void setNo_of_Songs(int no_of_Songs) {
this.no_of_Songs = no_of_Songs;
}
public String getArtists_Name() {
return artists_Name;
}
public void setArtists_Name(String artists_Name) {
this.artists_Name = artists_Name;
}
}
Custom method:
package com.org.Music_App.Repository;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
import com.org.Music_App.Albums.Album;
import com.org.Music_App.Artists.Artists;
public interface AlbumRepository extends CrudRepository<Album, Integer> {
public List<Album> findByArtists_Id(Integer artists_id) ;
}
Error:
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property artists found for type Album!
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:77) ~[spring-data-commons-1.13.6.RELEASE.jar:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'albumRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property artists found for type Album!
Can you retry the same code removing all underscores?
Java naming convention use camelcase and Spring assumes conventions in order to wire things properly.
if you have
#Id
private int albumId;
you have:
public int getAlbumId;
public void setAlbumId(int albumId);
etc.
PS: you don't need to define the artistsId property in the Album entity only because there will be an "artistis_id" column in the "album" table.
The AlbumRepository's findByArtists_Id method thinks that it needs to look up data based on artists instead of artist_Id, because it seems to be considering the String after "By" upto the underscore.
Try removing underscore and it may solve your issue.
It seems underscores doesn't work with the entity field names. Here is a similar question, where you can find a detailed answer: Spring-Data-Jpa Repository - Underscore on Entity Column Name
Hope that helps!
You have to define your repository here propertly, add #Repository here
#Repository
public interface AlbumRepository extends CrudRepository<Album, Integer> {
public List<Album> findByArtists_Id(Integer artists_id) ;
}
then it will start working
There is a little problem in replying on ajax requests. Initially, I have simplest restful service, based on spring boot MVC.
model:
import javax.persistence.*;
import java.util.*;
#Entity
#Table(name = "testmodel")
public class TestModel
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)//Postgresql sequence generator
private long id;
#Column(name = "name")
private String name;
#Column(name = "content")
private String content;
//Constructor
public TestModel()
{
}
//Id getter
public long getId()
{
return this.id;
}
//Name getter-setter
public String getName()
{
return this.name;
}
public void setName(String name)
{
this.name = name;
}
//Content getter-setter
public String getContent()
{
return this.content;
}
public void setContent(String content)
{
this.content = content;
}
}
DAO for model:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.*;
public interface TetsModelDAO extends JpaRepository<Samples, Long>
{
#Query("SELECT s FROM TestModel s WHERE LOWER(s.name) LIKE LOWER(:entry) ORDER BY s.name")
List<TestModel> fetchByNameEntry(#Param("entry") String entry);
}
Controller:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
#RequestMapping("/")
public class TestController
{
#Autowired
private TetsModelDAO testmodel;
#RequestMapping("/name")
public List<TestModel> getDatasetsByNameEntry(#RequestParam("entry") String entry)
{
return testmodel.fetchByNameEntry("%"+entry+"%");
}
}
Client-side ajax request:
$.ajax(
{
url : "/name?entry=", //get all records
method: "GET"
})
This example works perfectly - stringified reply looks like standart json structure:
{"id":"1", "name":"John", "content":"blablabla1"}
{"id":"2", "name":"Sam", "content":"blablabla2"}
{"id":"3", "name":"Ken", "content":"blablabla3"}
However, when I tried to define fileds in JPQL query explicitly (fetch, say, only id and name fields), I get wrong result in reply.
DAO with modified query (other code without changes):
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.*;
public interface TetsModelDAO extends JpaRepository<Samples, Long>
{
#Query("SELECT s.id, s.name FROM TestModel s WHERE LOWER(s.name) LIKE LOWER(:entry) ORDER BY s.name")
List<TestModel> fetchByNameEntry(#Param("entry") String entry);
}
In this case reply looks like this:
1, John, 2, Sam, 3, Ken
How to resolve this problem gracefully (without creating "helper classes")?
You can return DTO directly from Repository:
public interface TetsModelDAO extends JpaRepository<Samples, Long>
{
#Query("SELECT new mypackage.TestDto(s.id, s.name) FROM TestModel s WHERE LOWER(s.name) LIKE LOWER(:entry) ORDER BY s.name")
List<TestDto> fetchByNameEntry(#Param("entry") String entry);
}
where TestDto contains only required fields:
package mypackage;
public class TestDto {
private final long id;
private final String name;
public TestDto(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
}
Your query doesn't return instances of TestModel. It returns arrays of objects (i.e. a List<Object[]>), each array containing the ID and the name of a found TestModel. The correct query is
SELECT s FROM TestModel s WHERE LOWER(s.name) LIKE LOWER(:entry) ORDER BY s.name
You'd better implement automated tests to check that your DAO queries return what they should.