I am new to using CRUD Repository.
I have a database table with three columns:
course_id, name, course
I want to get a list of course_id give name, example,
SELECT id FROM table WHERE name='charmaine';
However, I do not want to do it with query but using crud repository.
There is an error shown in my controller.
May I know there is this error?
My controller
#GetMapping(value = "getting/{name}")
//#ResponseBody
public String getting(#PathVariable("name") String name) {
List<CourseMaster> getIds = CourseService.findIdByName(Name); —> error icon here
return getIds; —> error icon here
}
Service
public List<CourseMaster> findIdByName(String Name) {
return CourseMasterRepo.findByName(Name);
}
Repository
public interface CourseMasterRepo extends CrudRepository<CourseMaster, Long> {
List<CourseMaster> findByName(String Name);
}
You have to autowired service class in your controller like.
#Autowired
CourseService courseService;
#GetMapping(value = "getting/{name}")
public String getting(#PathVariable("name") String name) {
List<CourseMaster> getIds = courseService.findIdByName(Name);
return getIds;
}
if your code is done in java spring you must use hql language in hibernate, that is a interface of sql query.
hql query that use lambda expression is very simple and useful.
For example,
String hql = "FROM Employee E WHERE E.id = 10";
Query query = session.createQuery(hql);
List results = query.list();
Related
Is it possible to use JpaRepository without entity? In this case, replacing it with a DTO.
as follows the example
#Repository
public interface BffRepository extends JpaRepository<BffDTO, String> {
#Query(nativeQuery = true, value = "select\n"
+ "ent.name as enterprise_name, dep.name as department_name,\n"
+ "sq.name as squad_name, acc.firstname as job_owner_name,\n"
+ "tpt.name as test_template_name, job.name, job.job_blocked, job.job_removed,\n"
+ "job.bot_scm_branch, job.bot_scm_url, job.schedule_startdate,\n"
+ "job.expiration_date, job.timestamp,job.uuid,job.schedule_starttime,\n"
+ "tpt.job_execution_timeout\n"
+ "from portal.jobs job\n"
+ "left join portal.enterprises ent on (ent.uuid = job.enterprise_id)\n"
+ "left join portal.departments dep on (dep.uuid = job.department_id)\n"
+ "left join portal.squads sq on (sq.uuid = job.squad_id)\n"
+ "left join portal.accounts acc on (acc.uuid = job.job_owner)\n"
+ "left join portal.test_plan_templates tpt on (tpt.uuid = job.template_id) where\n"
+ "job.job_owner = ?1 and job.job_removed = false order by timestamp desc;")
List<BffDTO>buscarPorJobOwner(String jobOwner);
Are there alternatives for this case?
NOTE: the DTO is already mapped, but I would not like to create a view to transform this DTO into an Entity.
I already validated this topic, but without major advances
Use JpaRepository interaction style without entity
i'm trying this
Interface -
public interface BffDTOInterface2 {
String uuid();
String enterprise_name();
String department_name();
String squad_name();
String job_owner_name();
String test_template_name();
String name();
Boolean job_blocked();
Boolean job_removed();
String bot_scm_branch();
String bot_scm_url();
String schedule_startdate();
String expiration_date();
String timestamp();
String schedule_starttime();
Integer job_execution_timeout();
#Transient
String status();
}
I'm having this error
Caused by: java.lang.IllegalArgumentException: Not a managed type: interface br.com.cloud.api.domain.dto.BffDTOInterface2
You can use Projections based on interfaces.
e.g
Create your native-query givin it column a alias. select name as fullName, age as age from person.
Create a Interface that represents your DTO with get-methods to every alias of your native query.
interface MyDTO {
String getFullName();
Integer getAge();
}
The return type of your query now can be this MyDTO
#Query(value = "select name as fullName, age as age from person", nativeQuery=true)
List<MyDTO> findMyDTO();
Is it possible to use JpaRepository without entity?
No, it is not, and it would completely defeat the purpose of JPA, by definition.
JPA is the persistence specification that enables ORM - Object Relational Mapping - that is, you map Java objects to database tables' entries/rows, and Java types to database tables, respectively.
DTO (Data Transfer Object) has nothing to do with ORM, and it serves different purpose (I recommend you to read this article for DTO vs. Entity matter) - transferring data through Java objects - and it usually serves the middle layer, for converting persistent objects(#Entitys) into objects to be used in the web layer (DTOs), and vice versa.
If you really want to avoid persistence layer models (#Entitys), you may go for JDBC abstractions (e.g. Spring Data JDBC), native queries, JPQL, HQL, or a bare JDBC API (which I wouldn't recommend).
but you can try this.
What you can do is you can create your own custom repository class. First, you would have some service class that calls repository class. also notice that we have custom models for the result set of SQL queries.
#Service
public class CustomService {
#Autowired
private CustomRepository repository;
public List<CustomResponse> getAllResult(String id) {
List<Object[]> items = repository.getAllResult(id);
List<CustomResponse> customResponseList = new ArrayList();
for (Object[] item: items) {
CustomResponse c = new CustomResponse();
c.setTestValue1(String.valueOf(item[0]));
c.setTestValue2(String.valueOf(item[1]));
customResponseList.add(c);
}
return customResponseList;
}
}
and your repository class will be look like this.
#Repository
public class CustomRepository {
#Autowired
private EntityManager entityManager;
public List<Object[]> getAllResult(String id) {
Query q = (Query) entityManager.createNativeQuery("SELECT\n" +
" users.user_id as user_id,\n" +
" users.email as user_email\n" +
" FROM Users\n" +
" WHERE users.parent_id = :parent_id;");
q.setParameter("parent_id", id);
List<Object[]> results = q.getResultList();
return results;
}
}
Also you might want to have your own model for that. (like entities)
public class CustomResponse {
private String testValue1;
private String testValue2;
public String getTestValue1() {
return testValue1;
}
public void setTestValue1(String testValue1) {
this.testValue1 = testValue1;
}
public String getTestValue2() {
return testValue2;
}
public void setTestValue2(String testValue2) {
this.testValue2 = testValue2;
}
}
This is possible.
Define base entity and have one column. If you dont want this to exist in database, turn off ddl-auto in application.propeties.
spring.jpa.hibernate.ddl-auto=none
#Entity
#Data
public class BaseEntity {
#Id
private Long id;
}
and use any custom query with any other dao extending jpa repository with BaseEntity.
public interface EmployeeDao extends JpaRepository<BaseEntity, Long> {
#Query(value = "select name from employee where employee_number = ?", nativeQuery = true)
Optional<Employee> get(String employeeNumber);
}
public interface Employee{
String getName();
}
I want to run some native queries and expose the results through endpoints, but I want to do this without having to create all the entities. I just want the data obtained from the database to be exposed as it comes.
I found some suggestions at: Create spring repository without entity
However, I was not able to make them work. I'm very new to Spring.
I tried Maciej Kowalski's solution like this:
Interface:
public interface CustomNativeRepository {
Object runNativeQuery();
}
Implementation:
#Repository
public class CustomNativeRepositoryImpl implements CustomNativeRepository {
#Autowired
private EntityManager entityManager;
#Override
public Object runNativeQuery() {
return entityManager.createNativeQuery(
"""
SELECT 1 as col1, 2 as col2, 3 as col3
UNION ALL SELECT 4, 5, 6
UNION ALL SELECT 7, 8, 9
"""
)
.getResultList();
}
}
However, no endpoints were exposed, as happens when you extend CrudRepository. Should I have done something else with CustomNativeRepositoryImpl? I don't know how to proceed.
I also tried Gagarwa's solution:
RootEntity:
#Entity
public class RootEntity {
#Id
private Integer id;
}
RootEntityRepository:
#Repository
public interface RootEntityRepository extends JpaRepository<RootEntity, Integer> {
#Query(value = """
SELECT 1 as col1, 2 as col2, 3 as col3
UNION ALL SELECT 4, 5, 6
UNION ALL SELECT 7, 8, 9""",
nativeQuery = true)
public Collection<Object> findFromCustomQuery();
}
The endpoint http://localhost:8080/rootEntities was exposed, but when I accessed it, I got the exception: "Relation root_entity does not exist". So, I created the table in the database:
create table root_entity(
id SERIAL PRIMARY KEY
)
After that, the endpoint worked, and returned an empty array (the table root_entity is empty in the database).
I tried to access the endpoint: http://localhost:8080/rootEntities/search/findFromCustomQuery, but I got an exception (Couldn't find PersistentEntity for type class).
Again, I was not able to make it work.
After trying a lot, I made some progress doing the following:
#RestController
public class CustomQueryController {
#Autowired
private EntityManager entityManager;
#GetMapping("/myEndpoint")
#ResponseBody
public Object runNativeQuery() {
return ResponseEntity
.ok()
.body(
entityManager.createNativeQuery(
"""
SELECT 1 as col1, 2 as col2, 3 as col3
UNION ALL SELECT 4, 5, 6
UNION ALL SELECT 7, 8, 9
"""
).getResultList()
);
}
}
With the code above, I can access http://localhost:8080/myEndpoint and see the result of the query.
However, the endpoint didn't appear in the endpoints listing that is showed in http://localhost:8080/. I had to type it manually in the browser. I would like the endpoint to be exposed in order to see it in Swagger.
Also, I have a feeling that there must be a better way to do this. And I want to learn.
I would like help to:
Get a solution that works and exposes the endpoint.
Understand what I did wrong and how to implement Kowalski's and Gagarwa's solutions.
Being able to expose the endpoint for the last solution (CustomQueryController).
Thanks in advance!
try changing your CustomQueryController to implement RepresentationModelProcessor
public class CustomQueryController implements RepresentationModelProcessor<RepresentationModel<RepositoryLinksResource>> {
and implementing the process method with:
#Override
public RepresentationModel<RepositoryLinksResource> process(RepresentationModel<RepositoryLinksResource> model) {
if (model instanceof RepositoryLinksResource) {
model.add(Link.of( "http://localhost:8080" + "/myEndpoint", "myEndpoint"));
}
return model;
}
https://docs.spring.io/spring-data/rest/docs/current/reference/html/#customizing-sdr.customizing-json-output.representation-model-processor
I tried the first example that you have put here and it worked for me. But there is a bit of change. I have used PersistenceContext.
To return a Link as response I have used Link of WebMvcLinkBuilder.
Solution
In the below example I have used two tables Employee and Address in PostgresSQL . Both have area_code in common.
Interface
public interface CustomNativeRepository {
List<Object> runNativeQuery(Integer name);
}
Repository
#Repository
public class CustomNativeRepositoryImpl implements CustomNativeRepository {
Logger logger = LoggerFactory.getLogger(this.getClass());
#PersistenceContext
private EntityManager entityManager;
#Override
public List<Object> runNativeQuery(Integer areaCode) {
Query query = entityManager.createNativeQuery(
"Select e.first_name as name from employees e where e.area_code = ? "
+ "union all " +
"Select a.address as address from address a where a.area_code = ?");
query.setParameter(1, areaCode);
query.setParameter(2, areaCode);
List<Object> response = query.getResultList();
logger.info("Response from database: {}", response);
return response;
}
}
RestEndpoint Layer
#GetMapping(path ="/employee/{areaCode}")
public ResponseEntity<?> getEmployeeByCode(#PathVariable(value = "areaCode") Integer areaCode) throws NoSuchMethodException {
List<Object> response = customCustomerRepository.runNativeQuery(areaCode);
Link link = WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(EmployeeController.class).getEmployeeByCode(areaCode)).withSelfRel();
return ResponseEntity.ok().body(CollectionModel.of(response, link));
}
Few examples which may help. link1 link2
Note: I have not created any Entity classes in my code base.
public interface UserDao {
User getUserById(Long id);
void saveUser(User user);
List<UserDto> getAllUsers();
boolean isExistUserByEmail(String email);
boolean isExistUserByUserName(String userName);
// get users by id list
List<User> getUsersByIdIn(List<Long> idList);
// get all active users
List<UserDto> getAllActiveUsers();
User getUserByEmail(String email);
void saveAllUsers(List<User> userList);
List<Object[]> getAllInstructors();
}
This my dao impl method
#Override
public List<Object[]> getAllInstructors() {
return userRepository.getAllInstructors();
}
This is the query from my repository layer
#Query(value = "select distinct u.first_name, u.last_name, u.full_name, u.id from public.user u inner join public.users_group ug on u.id = ug.user_id and ug.group_list_id=1 WHERE status=1 ORDER BY u.id DESC", nativeQuery = true)
This is the method in my controller layer
#GetMapping("/instructors")
public List<Object[]> getAllIntsructors() {
return userService.getAllInstructors();
}
Result when I call the api on postman
The result I expect is:
first_name: "Iresha"
second_name: "Vishwakala"
But I don't get the key. I only get an array of objects showing me the values.
The way you are using your Repo is not a good practice. To be honest I have never seen it before.
This would be the correct way to do it:
public interface UserRepository extends JpaRepository<UserEntity, Long> // Here the first is the Entity which will be fetched by this repo, and the second is the type of ID that this Entity has.
{
// I am supposing that your entity is UserEntity and has an ID of type Long.
// Here come the queries which must return primitives or UserEntity (list, set etc.)
// An example query would be:
#Query(value = "....", nativeQuery = true) List<UserEntity> getUsersAsYouWant();
}
The JpaRepository makes use of Java Generics (hence the <>), that is why you must supply the class the types that it has to map the DB rows/data to. If you want to return specific types/Dtos/List you may use the same Repo but with different Query building (not native but JPQL). But that would be yet another question. If you want to check more, see my answer here.
I have to execute a SQL query in my repository:
public interface UserRequestResponseRepository extends JpaRepository<UserRequestResponse, Integer> {
//public static final String FIND_QUERY = "select user.u_httpstatus ,user.u_queryparam from UserRequestResponse user";
public static final String FIND_QUERY =
"select new com.abc.datacollection.entity.UserRequestResponse(user.u_httpstatus ,user.u_queryparam) from UserRequestResponse user";
#Query(value = FIND_QUERY)
public List<UserProjection> getAllRequestResponseRecords();
}
where UserProjection is a projection that I defined:
public interface UserProjection {
String getU_httpstatus();
String getU_queryparam();
}
The class userRequestResponse has more fields than u_httpstatus and u_queryparam, but I want only these 2 fields in my response.
public #ResponseBody List<UserRequestResponse> getAllRequestResponseRecords() {
return userRequestResponseRepository.findAll() ;
}
how do I modify the above code (findAll()) to get results from my custom query and not the results from the default CrudRepository findAll() (which returns all the fields).
First you don't need to add a #Query to make projections work. Just having the UserProjection as the return type of the method in repository should be enough. More about this here
Secondly, you can just have the following method in your repository as a projection-based findAll method;
public List<UserProjection> findAllProjectedBy();
On the internet I found that Spring can do pagination as well as ordering for a list of data retrieved from the database. Accordingly, I created my test class as following:
#Test
public void testPageable() {
int pageSize = 5;
Sort sort = new Sort( Direction.DESC, "someColumnA" );
Pageable pageable = new PageRequest( 0, pageSize, sort );
List<SomeObject> listOFSomeObject = getDao().getListData( "paramOne", pageable );
}
When I analyze the List I never get ordering of someColumnA in a DESC fashion, although I get back only 5 records which is correct.
Can someone please let me know what I might be doing wrong? Just as an FYI, I am using Hibernate for database access and Spring named query.
EDIT:
Code for getListData()->
public interface SomeRepository
extends JpaRepository<EntityMappedViaHibernate, String> {
List<Object[]> getListData( #Param(value = PARAM_ONE) final String paramOne, Pageable pageable );
}
My Hibernate entity is as follows:
#NamedQueries(value = {
#NamedQuery(name = "SomeRepository.getListData", query = "select id, someColumnA from EntityMappedViaHibernate where id = :paramOne")
})
#Entity
#Table(name = "entity_mapped_via_hibernate")
public class EntityMappedViaHibernate implements Serializable {
// Code Omitted on purpose
}
So those of you who are struggling like me the solution to this problem is that you need to have the query inside the Repository. In my case it has to be inside the SomeRepository. So in the code of the repo do the following:
public interface SomeRepository
extends JpaRepository<EntityMappedViaHibernate, String> {
#Query("select id, someColumnA from EntityMappedViaHibernate where id = :paramOne")
List<Object[]> getListData( #Param(value = PARAM_ONE) final String paramOne, Pageable pageable );
}
No need to have the NamedQuery inside the EntityMappedViaHibernate. That's it!!
Hope someone find the answer and do not struggle like I did.