Use native query with Spring Projection Interface to select fields - java

I want to know how can I populate these classes:
interface BaseDTO {
Integer getId();
String getNome();
Boolean getAtivo();
RegionalDTO getRegional();
MunicipioDTO getMunicipio();
}
interface RegionalDTO {
Integer getId();
}
interface MunicipioDTO {
Integer getId();
}
And run this query
#Query(value = "SELECT " +
"base.ID_BASE AS id, base.NOME AS nome, base.ATIVO AS ativo, " +
"regional.ID_REGIONAL AS ID_REGIONAL, " +
"municipio.ID_MUNICIPIO AS ID_MUNICIPIO " +
"FROM TB_BASE base " +
"LEFT JOIN TB_REGIONAL regional on base.ID_REGIONAL = regional.ID_REGIONAL " +
"LEFT JOIN TB_MUNICIPIO municipio on base.ID_MUNICIPIO = municipio.ID_MUNICIPIO " +
"ORDER BY base.ID_BASE", nativeQuery = true)
List<BaseDTO> getAll();
So I want to select the fields in the query, because later I will put more fields in theses DTO.

I think that the simplest way would be to use simple interface with only ids for regional and municipio. After calling getAll map this interface to appropriate class structure (where ids turn into dtos).
List<RealDTO> result = repository.getAll().stream()
.map(i -> new RealDTO(i))
.collect(Collectors.toList());

First, I need to convert my DTOS, to class
#Value
public class BaseDTO {
private Integer id;
private String nome;
private MunicipioDTO municipio;
private RegionalDTO regional;
public BaseDTO(Integer id, String nome, Integer municipioId, Integer regionalId) {
this.id = id;
this.nome = nome;
this.municipio = new MunicipioDTO(municipioId);
this.regional = new RegionalDTO(regionalId);
}
}
#Value
public class MunicipioDTO {
private Integer id;
}
#Value
public class RegionalDTO {
private Integer id;
}
So in my repository I did it
#Query(value = "SELECT new com.apivgosmobile.dto.model.BaseDTO(base.id, base.nome, municipio.id, regional.id)" +
"FROM Base base " +
"LEFT JOIN base.municipio municipio " +
"LEFT JOIN base.regional regional " +
"WHERE base.ativo = 1 " +
"ORDER BY base.id ASC")
List<BaseDTO> getAll();

Related

How to Update a SQL database Table if the entity is Persistable in Spring Boot JPA

I have created a Spring Boot JPA Application, In that, I have made an entity persistable.
as Shown Below.
this is my code for creating an entity:
#Getter
#Setter
#ToString
#Entity
public class TableModel implements Persistable<String> {
#Override
public String toString() {
return "TableModel [PrimaryKey=" + PrimaryKey + ", Term_Guid=" + Term_Guid + ", Term_Name=" + Term_Name
+ ", Term_Description=" + Term_Description + ", Term_Qualified_Name=" + Term_Qualified_Name
+ ", Term_Status=" + Term_Status + ", Term_Created_Date=" + Term_Created_Date + ", Term_Updated_Date="
+ Term_Updated_Date + ", Report_name=" + Report_name + ", Report_Guid=" + Report_Guid + ", Report_Type="
+ Report_Type + ", classification=" + classification + ", Term_Expert_Username=" + Term_Expert_Username
+ ", Term_Steward_Username=" + Term_Steward_Username + ", Report_Expert_Username="
+ Report_Expert_Username + ", Report_Owner_Username=" + Report_Owner_Username + ", Sql_db_load_time="
+ Sql_db_load_time + "]";
}
#Id
#Column(name = "Primary_Key")
private String PrimaryKey;
#Column(name = "Term_Guid")
private String Term_Guid;
#Column(name = "Term_Name")
private String Term_Name;
#Column(name = "Term_Description",columnDefinition = "nvarchar(MAX)")
private String Term_Description;
#Column(name = "Term_Qualified_Name")
private String Term_Qualified_Name;
#Column(name = "Term_Status")
private String Term_Status;
#Temporal(TemporalType.TIMESTAMP)
private java.util.Date Term_Created_Date;
#Temporal(TemporalType.TIMESTAMP)
private java.util.Date Term_Updated_Date;
#Column(name = "Report_name")
private String Report_name;
#Column(name = "Report_Guid")
private String Report_Guid;
#Column(name = "Report_Type")
private String Report_Type;
#Column(name = "Classification")
private String classification;
#Column(name = "Term_Expert_Username")
private String Term_Expert_Username;
#Column(name = "Term_Steward_Username")
private String Term_Steward_Username;
#Column(name = "Report_Expert_Username")
private String Report_Expert_Username;
#Column(name = "Report_Owner_Username")
private String Report_Owner_Username;
#Temporal(TemporalType.TIMESTAMP)
private java.util.Date Sql_db_load_time;
#Override
public boolean isNew() {
// TODO Auto-generated method stub
return true;
}
#Override
public String getId() {
// TODO Auto-generated method stub
return null;
}
}
By using this Code I am able to insert data successfully
but if I want to update the data which is inserted I m not able do,
Please Suggest how I can update the data if the entity is persistable using Springboot jpa
If you are not clear how to fire update queries with spring data jpa,
You can refer this document for partial updates:
https://www.baeldung.com/spring-data-partial-update
You can also refer spring data jpa documentation.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.modifying-queries
I suggest you keep your entity simple, then create a repository that extends JpaRepository or CrudRepository where you can write your queries
#Repository
public interface TableModelRepository extends JpaRepository<TableModel, String>{
#Modifying
#Query("update TableModel u set u.firstname = ?1 where u.lastname = ?2")
void updateTable(String firstname, String lastname);
}
create a service class where you can perform the update
#Service
public class TableModelServices{
#Autowired
private TableModelRepository tableModelRepository;
#Override
public String updateTable(String firstname, String lastname) {
tableModelRepository.updateTable(firstname, lastname);
return null;
}
}
the above codes are for reference, I will mention some links which will help you more
https://www.baeldung.com/spring-data-jpa-dynamicupdate
https://www.baeldung.com/spring-data-partial-update
you can refer to these two links.

Cannot get or create PersistentEntity for type

I've been trying to expose some services through the Spring JPARepository interface
So I created a StudentRepo like this:
package edu.university.management.dao;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.rest.core.annotation.RestResource;
import edu.university.management.model.Student;
import edu.university.management.model.StudentsPerDepartment;
public interface StudentRepository extends JpaRepository<Student, Long> {
#RestResource(path = "/byDeptOrdered")
//#Query("select s from Student s where s.department.name = 'Informatique' order by s.entryDate desc")
public List<Student> findByDepartment_NameOrderByEntryDateDesc(String deptName);
#RestResource(path = "/topStudents")
#Query("select s"
+ " from Student s"
+ " where s.mark = ("
+ "select max(s.mark)"
+ " from Student s"
+ ")")
public List<Student> topStudents();
#RestResource(path = "/studentsPerDept")
#Query("select new edu.university.management.model.StudentsPerDepartment(d.name, count(s))"
+ " from Department d"
+ " left join"
+ " d.students s"
+ " group by d.name")
public List<StudentsPerDepartment> studentCountPerDepartment();
}
For the last service studentCountPerDepartment I used a class based projection to avoid returning an array of Objects,
StudentsPerDepartment:
package edu.university.management.model;
public class StudentsPerDepartment {
private String departmentName;
private Long studentCount;
public StudentsPerDepartment(String departmentName, Long studentCount) {
super();
this.departmentName = departmentName;
this.studentCount = studentCount;
}
public String getDepartmentName() {
return departmentName;
}
public Long getStudentCount() {
return studentCount;
}
}
But when i invoke the service i get this error:
org.springframework.data.mapping.MappingException: Cannot get or create PersistentEntity for type edu.university.management.model.StudentsPerDepartment! PersistentEntities knows about 2 MappingContext instances and therefore cannot identify a single responsible one. Please configure the initialEntitySet through an entity scan using the base package in your configuration to pre initialize contexts.
Any ideas guys?
Thank you.

Using jdbcTemplate.query with parameters

I have 3 tables in Database Lecture--< LectureGroups >-- Groups.
And I want to get schedule for a certain group on a certain day. I try to do it in this way:
#Repository
public class Schedule {
private static final String GET_GROUP_DAY_SCHEDULE = "SELECT * FROM LECTURES " +
"INNER JOIN LECTUREGROUPS ON LECTURES.ID = LECTUREGROUPS.LECTUREID " +
"INNER JOIN GROUPS ON GROUPS.ID = LECTUREGROUPS.GROUPID " +
"WHERE GROUPID = :GROUPID AND DATE = :DATE";
#Autowired
private JdbcTemplate jdbcTemplate;
public List<Lecture> getGroupDayLectures(int groupId, LocalDateTime dateTime) {
MapSqlParameterSource parameters = new MapSqlParameterSource()
.addValue("groupid", groupId)
.addValue("date", dateTime);
return jdbcTemplate.query(GET_GROUP_DAY_SCHEDULE, new BeanPropertyRowMapper<>(Lecture.class), parameters);
}
}
But I get an exception in query raw
Caused by: org.postgresql.util.PSQLException: Can't infer the SQL type to use for an instance of org.springframework.jdbc.core.namedparam.MapSqlParameterSource. Use setObject() with an explicit Types value to specify the type to use.
How I can fix it?
I also used variant with
private static final String GET_GROUP_DAY_SCHEDULE = "SELECT * FROM LECTURES " +
"INNER JOIN LECTUREGROUPS ON LECTURES.ID = LECTUREGROUPS.LECTUREID " +
"INNER JOIN GROUPS ON GROUPS.ID = LECTUREGROUPS.GROUPID " +
"WHERE GROUPID = ? AND DATE = ?";
#Autowired
private JdbcTemplate jdbcTemplate;
public List<Lecture> getGroupDayLectures(int groupId, LocalDateTime dateTime) {
return jdbcTemplate.query(GET_GROUP_DAY_SCHEDULE, new Object[]{groupId, dateTime}, new BeanPropertyRowMapper<>(Lecture.class));
}
and it works but return only 1 Lecture in list (it must be 3)
There is a signature with parameters in the jdbcTemplate class:
public <T> List<T> query(String sql, RowMapper<T> rowMapper, #Nullable Object... args)
So it is very easy to use it in this way
private static final String GET_GROUP_DAY_SCHEDULE = "SELECT * FROM LECTURES " +
"INNER JOIN LECTUREGROUPS ON LECTURES.ID = LECTUREGROUPS.LECTUREID " +
"INNER JOIN GROUPS ON GROUPS.ID = LECTUREGROUPS.GROUPID " +
"WHERE GROUPID = ? AND DATE = ?";
#Autowired
private JdbcTemplate jdbcTemplate;
public List<Lecture> getGroupDayLectures(int groupId, LocalDate date) {
return jdbcTemplate.query(GET_GROUP_DAY_SCHEDULE, new BeanPropertyRowMapper<>(Lecture.class), groupId, date);
}

How to implement Server-side processing of DataTables with JDBC so that it paginates?

I have a Spring Boot app with DataTables server-side processing and Oracle database. Actually, I started with implementing one of the tutorials. It worked. The tutorial uses JPA. I want to implement the same using JDBC. I made all the corresponding classes, the repository, the new model with same filds but without jpa. But when I tried to fetch the data, it allowed me to get only the first page without a chance to get to the second page. Below I will post the extracts of the original and added code. So, the original tutorial used these classes:
#Entity
#Table(name = "MYUSERS")
public class User {
#Id
#Column(name = "USER_ID")
private Long id;
#Column(name = "USER_NAME")
private String name;
#Column(name = "SALARY")
private String salary;
...getters and setters
}
And
#Entity
public class UserModel {
#Id
private Long id;
private String name;
private String salary;
private Integer totalRecords;
#Transient
private Integer rn;
...getters and setters
}
And I substituted these two classes with one like this:
public class NewUser {
private Long id;
private String name;
private String salary;
private Integer totalRecords;
private Integer rn;
...getters and setters
}
The table itself has only 3 fields: id, name and salary, the other 2 fields are created and filled later.
The repositiry the original Author has for the user looks like this:
public interface UserRepository extends JpaRepository<User, Long> {
#Query(value = "SELECT * FROM MYUSERS", nativeQuery = true)
List<User> findAllByUsernames(List<String> listOfUsernames);
}
My own repository looks like this:
#Repository
public class NewUserRepoImpl extends JdbcDaoSupport implements NewUserRepo {
private static final String SELECT_ALL_SQL = "SELECT USER_ID as id, USER_NAME as name, SALARY as salary FROM MYUSERS";
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private final JdbcTemplate jdbctemplate;
public NewUserRepoImpl(NamedParameterJdbcTemplate namedParameterJdbcTemplate, JdbcTemplate jdbctemplate, DataSource dataSource) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
this.jdbctemplate = jdbctemplate;
setDataSource(dataSource);
}
#Override
public List<NewUser> findAll(PaginationCriteria pagination) {
try {
String paginatedQuery = AppUtil.buildPaginatedQueryForOracle(SELECT_ALL_SQL, pagination);
return jdbctemplate.query(paginatedQuery, newUserRowMapper());
} catch (DataAccessException e) {
throw new EntityNotFoundException("No Entities Found");
}
}
#Bean
public RowMapper<NewUser> newUserRowMapper() {
return (rs, i) -> {
final NewUser newUser = new NewUser();
newUser.setId(rs.getLong("ID"));
newUser.setName(rs.getString("NAME"));
newUser.setSalary(rs.getString("SALARY"));
newUser.setTotalRecords(rs.getInt("TOTAL_RECORDS"));
newUser.setTotalRecords(rs.getInt("RN"));
return newUser;
};
}
}
the buildPaginatedQueryForOracle thing transforms my Query and allows it to get the totalRecords and rn. Below I will post the output of it both for the orifinal and my queries (they are the same, I checked).
So, the main part, the controller. I left the old and new pieces in it for now for debug purposes and just returning one of the results:
#RequestMapping(value="/users/paginated/orcl", method=RequestMethod.GET)
#ResponseBody
public String listUsersPaginatedForOracle(HttpServletRequest request, HttpServletResponse response, Model model) {
DataTableRequest<User> dataTableInRQ = new DataTableRequest<User>(request);
System.out.println(new Gson().toJson(dataTableInRQ));
DataTableRequest<NewUser> dataTableInRQNew = new DataTableRequest<NewUser>(request);
System.out.println(new Gson().toJson(dataTableInRQNew));
PaginationCriteria pagination = dataTableInRQ.getPaginationRequest();
System.out.println(new Gson().toJson(pagination));
PaginationCriteria paginationNew = dataTableInRQNew.getPaginationRequest();
System.out.println(new Gson().toJson(paginationNew));
String baseQuery = "SELECT USER_ID as id, USER_NAME as name, SALARY as salary FROM MYUSERS";
String paginatedQuery = AppUtil.buildPaginatedQueryForOracle(baseQuery, pagination);
String paginatedQueryNew = AppUtil.buildPaginatedQueryForOracle(baseQuery, paginationNew);
System.out.println(paginatedQuery);
System.out.println(paginatedQueryNew);
Query query = entityManager.createNativeQuery(paginatedQuery, UserModel.class);
System.out.println("Query:");
System.out.println(query);
#SuppressWarnings("unchecked")
List<UserModel> userList = query.getResultList();
System.out.println(new Gson().toJson(userList));
#SuppressWarnings("unchecked")
List<NewUser> userListNew = newUserRepo.findAll(paginationNew);
System.out.println(new Gson().toJson(userListNew));
DataTableResults<UserModel> dataTableResult = new DataTableResults<UserModel>();
DataTableResults<NewUser> dataTableResultNew = new DataTableResults<NewUser>();
dataTableResult.setDraw(dataTableInRQ.getDraw());
dataTableResultNew.setDraw(dataTableInRQNew.getDraw());
dataTableResult.setListOfDataObjects(userList);
dataTableResultNew.setListOfDataObjects(userListNew);
if (!AppUtil.isObjectEmpty(userList)) {
dataTableResult.setRecordsTotal(userList.get(0).getTotalRecords()
.toString());
if (dataTableInRQ.getPaginationRequest().isFilterByEmpty()) {
dataTableResult.setRecordsFiltered(userList.get(0).getTotalRecords()
.toString());
} else {
dataTableResult.setRecordsFiltered(Integer.toString(userList.size()));
}
}
if (!AppUtil.isObjectEmpty(userListNew)) {
dataTableResultNew.setRecordsTotal(userListNew.get(0).getTotalRecords()
.toString());
if (dataTableInRQ.getPaginationRequest().isFilterByEmpty()) {
dataTableResultNew.setRecordsFiltered(userListNew.get(0).getTotalRecords()
.toString());
} else {
dataTableResultNew.setRecordsFiltered(Integer.toString(userListNew.size()));
}
}
System.out.println(new Gson().toJson(dataTableResult));
System.out.println(new Gson().toJson(dataTableResultNew));
return new Gson().toJson(dataTableResult);
}
So, I log out everything possible in the console. Here is the output:
{"uniqueId":"1579786571491","draw":"1","start":0,"length":5,"search":"","regex":false,"columns":[{"index":0,"data":"id","name":"ID","searchable":true,"orderable":true,"search":"","regex":false,"sortDir":"ASC"},{"index":1,"data":"name","name":"Name","searchable":true,"orderable":true,"search":"","regex":false},{"index":2,"data":"salary","name":"Salary","searchable":true,"orderable":true,"search":"","regex":false}],"order":{"index":0,"data":"id","name":"ID","searchable":true,"orderable":true,"search":"","regex":false,"sortDir":"ASC"},"isGlobalSearch":false,"maxParamsToCheck":3}
{"uniqueId":"1579786571491","draw":"1","start":0,"length":5,"search":"","regex":false,"columns":[{"index":0,"data":"id","name":"ID","searchable":true,"orderable":true,"search":"","regex":false,"sortDir":"ASC"},{"index":1,"data":"name","name":"Name","searchable":true,"orderable":true,"search":"","regex":false},{"index":2,"data":"salary","name":"Salary","searchable":true,"orderable":true,"search":"","regex":false}],"order":{"index":0,"data":"id","name":"ID","searchable":true,"orderable":true,"search":"","regex":false,"sortDir":"ASC"},"isGlobalSearch":false,"maxParamsToCheck":3}
{"pageNumber":0,"pageSize":5,"sortBy":{"mapOfSorts":{"id":"ASC"}},"filterBy":{"mapOfFilters":{},"globalSearch":false}}
{"pageNumber":0,"pageSize":5,"sortBy":{"mapOfSorts":{"id":"ASC"}},"filterBy":{"mapOfFilters":{},"globalSearch":false}}
SELECT * FROM (SELECT FILTERED_ORDERED_RESULTS.*, COUNT(1) OVER() total_records, ROWNUM AS RN FROM (SELECT BASEINFO.* FROM ( SELECT USER_ID as id, USER_NAME as name, SALARY as salary FROM MYUSERS ) BASEINFO ) FILTERED_ORDERED_RESULTS ORDER BY id ASC ) WHERE RN > (0 * 5) AND RN <= (0 + 1) * 5
SELECT * FROM (SELECT FILTERED_ORDERED_RESULTS.*, COUNT(1) OVER() total_records, ROWNUM AS RN FROM (SELECT BASEINFO.* FROM ( SELECT USER_ID as id, USER_NAME as name, SALARY as salary FROM MYUSERS ) BASEINFO ) FILTERED_ORDERED_RESULTS ORDER BY id ASC ) WHERE RN > (0 * 5) AND RN <= (0 + 1) * 5
Query:
org.hibernate.query.internal.NativeQueryImpl#3ea49a4
[{"id":3,"name":"user3","salary":"300","totalRecords":18},{"id":4,"name":"user4","salary":"400","totalRecords":18},{"id":5,"name":"user5","salary":"500","totalRecords":18},{"id":6,"name":"user6","salary":"600","totalRecords":18},{"id":7,"name":"user7","salary":"700","totalRecords":18}]
[{"id":3,"name":"user3","salary":"300","totalRecords":1},{"id":4,"name":"user4","salary":"400","totalRecords":2},{"id":5,"name":"user5","salary":"500","totalRecords":3},{"id":6,"name":"user6","salary":"600","totalRecords":4},{"id":7,"name":"user7","salary":"700","totalRecords":5}]
{"draw":"1","recordsFiltered":"18","recordsTotal":"18","data":[{"id":3,"name":"user3","salary":"300","totalRecords":18},{"id":4,"name":"user4","salary":"400","totalRecords":18},{"id":5,"name":"user5","salary":"500","totalRecords":18},{"id":6,"name":"user6","salary":"600","totalRecords":18},{"id":7,"name":"user7","salary":"700","totalRecords":18}]}
{"draw":"1","recordsFiltered":"1","recordsTotal":"1","data":[{"id":3,"name":"user3","salary":"300","totalRecords":1},{"id":4,"name":"user4","salary":"400","totalRecords":2},{"id":5,"name":"user5","salary":"500","totalRecords":3},{"id":6,"name":"user6","salary":"600","totalRecords":4},{"id":7,"name":"user7","salary":"700","totalRecords":5}]}
It helped me realize that:
DataTableRequest incoming from the back is the same for both jpa
and jdbc
PaginationCriteria are also the same
paginatedQuery
having been made with the method specified above are the same.
Differences are already seen in the Lists: where the Jpa list
retrieved with native Query has totalRecords as 18 for every row,
the JDBC repo with the same query returns 1,2,3... for every
subsequent row.
It made me think that I should look at the Query made for JPA. But, as you see in the log, System.out.println wasn't able to decipher it for some reason.
Any advice on how to decipher it and more importantly how to get the right total result for each row would be greatly appreciated!!!

Filtering Model objects by a ManytoMany relation in Play! 2.0

I have a simple model with a manytomany relation and a function, rendering Model Pages as you can see below. I want to know if there's a way to filter item pages by categories (ManytoMany field) something like .ilike("categories", "%" + filter + "%")
public class Item extends Model {
#Id
public Long id;
#ManyToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
public List<Category> categories = new ArrayList<Category>();
public String title;
#Formats.DateTime(pattern="dd/MM/yyyy")
public Date postDate=new Date();
public String content;
public String picture;
public String price;
public String url;
public static Finder<Long,Item> find = new Finder<Long,Item>(
Long.class, Item.class
);
public static Page<Item> page(int page, int pageSize, String sortBy, String order, String filter) {
return
find.where()
.ilike("content", "%" + filter + "%")
.orderBy(sortBy + " " + order)
.findPagingList(pageSize)
.getPage(page);
}
}
That was similar question just a few topics ago and you can use a sample from it (and also check other possibility for relation filtering)
your query should look like this (to find Items which contains Categories that contains 'some' word in their name) :
find.where()
.ilike("categories.name", "%some%")
.orderBy(sortBy + " " + order)
.findPagingList(pageSize)
.getPage(page);

Categories