How to use Spring Data JPA findAll method in Spring Boot with custom parameter? - spring-boot

I have a Entity class
#Entity
public class SampleEntity {
#Id
#Column(name = "ID")
private Long id;
#NotNull
#Column(length = 2000)
private String name;
#NotNull
#Column(length = 2000)
private String type;
#NotNull
#Column(length = 2000)
private String something;
// getters and setters
}
What I need is to findAll by the custom column of my entity type
how I can achieve this in Spring boot and JpaRepository

Follow https://docs.spring.io/spring-data/jpa/docs/1.5.0.RC1/reference/html/jpa.repositories.html which will list all possible method to find out records from DB.
For your problem , use List<SampleEntity> findByType(String type) in your repository. This method will return all SampleEntity by type values passed in query.

Besides the findByType(String type) you can use the Spring Data repository syntax to fine tune your queries, using the same parameter String type.
Some examples:
findByTypeIgnoreCase: will return all that match the given type string ignoring case differences between that string and the SampleEntity type field.
findFirstByType: will return the first element with the given type if there is any.
findFirst100ByType: will return the first 100 elements.
findByTypeOrderByIdAsc: will return all SampleEntity with the given type, in ascending order by their id field.
countByType: will return the number of SampleEntity with the given type.
removeByType: will delete all the SampleEntity with that type.

Related

Error - No Dialect mapping for JDBC type: 1111 while using Projection in JPARepository for jsonb type column

I have a jsonb column in my postgres db When I use findAll() method of JPA Repository to retrieve all data everything works like charm.
My Entity is as follows
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "steps")
public class Steps {
#EmbeddedId
private StepsId id;
#Column(name = "steps_name")
private String steps_name;
#Column(name = "sub_steps",columnDefinition = "jsonb")
#Convert(converter = SubStepsConverter.class)
private List<Substeps> sub_steps;
#Column(name = "status")
private String status;
}
When I use a Projection to retrieve selected data then it gives error No Dialect mapping for JDBC type: 1111
public interface StepsProjection {
String getid();
String getSteps_name();
#Convert(converter = SubStepsConverter.class)
List<Substeps> getSub_steps();
}
So if I remove List<Substeps> getSub_steps(); from above class and from my query everything works good so I guess the issue is with sub_steps field only which is a jsonb field while using Projection?
I have tried changing the Type to String in NotesProjection for substeps but no result.
I need to return only selected fields to the client.

Spring JPA bidirectional relation on multiple nested entities

I know there has been multiple questions on bidirectional relations using spring jpa in the past but my case is a little bit different because i am using 3 entities with 2 relationships to implement a medical system
I have 3 entities : doctor/patient/appointment
here is the code for the 3 entities
please note all setters , getters and constructors implemented but ommited here for clarity
Patient class
#Entity
public class resPatient {
#Id
#GeneratedValue( strategy= GenerationType.IDENTITY )
private long code;
private String name;
private String gender;
private String email;
private String mobile;
private int age;
private String notes;
#OneToMany(mappedBy = "patient")
List<resPackageMembership> memberships;
#OneToMany(mappedBy = "patient")
List<resAppointment> appointments;
#OneToMany(fetch = FetchType.LAZY,mappedBy = "patient")
List<resMedImage> medImages;
Doctor class
#Entity
public class resDoctor {
#Id
#GeneratedValue( strategy= GenerationType.IDENTITY )
private long code;
private String name;
private String mobile;
private String email;
private String gender;
private int age;
private String speciality;
#OneToMany(mappedBy = "doctor")
List<resAppointment> appointments;
Appointment class
#Entity
public class resAppointment {
#Id
#GeneratedValue( strategy= GenerationType.IDENTITY )
private long code;
private String speciality;
#Basic
#Temporal(TemporalType.TIMESTAMP)
private Date dateCreated;
#Basic
#Temporal(TemporalType.TIMESTAMP)
private Date dateToVisit;
private String status;
private String notes;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "doctorCode")
private resDoctor doctor;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "patientCode")
private resPatient patient;
the way my medical system should work is that when i get a patient using my restful controller i want all the patient data including his appointments but this leads to an infinite loop as the appointment has the doctor which also has appointments and so on.
i cannot user #JSONIGNORE as there are 2 relationships i want to get the patient with his appointments which should have the doctor without the appointments array and should not have any patient data as i already am in the patient object
As a general best-practice, it's recommended to separate the entities from the data transfer objects used for the rest controllers. With DTO's in place, you have more control on which data to include and serialize within them to avoid the circlular references.
If you like check out https://bootify.io, it generates the DTOs from your database schema, but the custom endpoint you still need to define/build.
I develop an annotation processor called beanknife recently, it support generate DTO from any class. You need config by annotation. But you don't need change the original class. This library support configuring on a separate class. Of course you can choose which property you want and which you not need. And you can add new property by the static method in the config class. For your question:
// this will generate a DTO class named "resPatientView".
// You can change this name using genName attribute.
#ViewOf(value=resPatient.class, includePattern = ".*")
public class PatientViewConfigure {
// here tell the processor to automatically convert the property appointments from List<resAppointment> to List<resAppointmentWithoutPatient>.
// resAppointmentWithoutPatient is the generated class configured at the following.
// Note, although at this moment it not exists and your idea think it is an error.
// this code really can be compiled, and after compiled, all will ok.
#OverrideViewProperty("appointments")
private List<resAppointmentWithoutPatient> appointments;
}
// here generated a class named resAppointmentWithoutPatient whick has all properties of resAppointment except patient
#ViewOf(value=resAppointment.class, genName="resAppointmentWithoutPatient", includePattern = ".*", excludes={"patient"})
public class AppointmentWithoutPatientViewConfigure {
// the doctor property will be converted to its dto version which defined by the configure class DoctorWithoutAppointmentsViewConfigure.
#OverrideViewProperty("doctor")
private resDoctorWithoutAppointments doctor;
}
// here we generate a class which has all properties of resDoctor except appointments
#ViewOf(value=resDoctor.class, genName="resDoctorWithoutAppointments", includePattern = ".*", excludes={"appointments"})
public class DoctorWithoutAppointmentsViewConfigure {}
// in you rest controller. return the dto instead of the entities.
resPatient patient = ...
resPatientView dto = resPatientView.read(patient);
List<resPatient> patients = ...
List<resPatientView> dto = resPatientView.read(patients);
At the end, the class resPatientView will has the same shap with resPatient except its appointments not having patient property and its doctor property is replaced with a version without appointments property.
Here are more examples.
The version 1.10 is ready. Will fix some bug and support the configure bean to be managed by spring.

Retrieving foreign key attributes in DTO

I am using java+Spring framework+Hibernate for creating rest api but I have stumbled upon retrieving details of a table using foreign key attributes.
I have the following tables::
https://i.stack.imgur.com/lG7UR.png
I am retrieving all the ratings given using product id and then mapping to DTO, now I also want to populate the username using idusers as this is my foreign key.
Same is the case when I try to retrieve ratings given by the users, instead of displaying idproducts I want to display the product name and product description as It is a foreign key.
Any advice on how to do so using DTO's.
This is a perfect use case for Blaze-Persistence Entity Views.
Blaze-Persistence is a query builder on top of JPA which supports many of the advanced DBMS features on top of the JPA model. I created Entity Views on top of it to allow easy mapping between JPA models and custom interface defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure the way you like and map attributes(getters) via JPQL expressions to the entity model. Since the attribute name is used as default mapping, you mostly don't need explicit mappings as 80% of the use cases is to have DTOs that are a subset of the entity model.
Assuming you have an entity model like this
#Entity
public class User {
#Id
Integer id;
String role;
String username;
String password;
boolean enabled;
}
#Entity
public class Product {
#Id
Integer id;
String imageUrl;
String category;
int productPrice;
int productQuantity;
String productName;
String productDesc;
#OneToMany(mappedBy = "product")
Set<Rating> ratings;
}
#Entity
public class Rating {
#Id
Integer id;
int rating;
String review;
String ratingscol;
#ManyToOne(fetch = LAZY)
Product product;
#ManyToOne(fetch = LAZY)
User user;
}
A DTO mapping for your model could look as simple as the following
#EntityView(Rating.class)
interface RatingDto {
Integer getId();
UserDto getUser();
ProductDto getProduct();
}
#EntityView(User.class)
interface UserDto {
Integer getId();
String getUsername();
}
#EntityView(Rating.class)
interface ProductDto {
Integer getId();
String getProductName();
String getProductDesc();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
RatingDto dto = entityViewManager.find(entityManager, RatingDto.class, id);
But the Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
It will only fetch the mappings that you tell it to fetch
You can use ModelMapper when converting a DTO to an Entity bean and back from Entity bean to a DTO.
Add ModelMapper to your project
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.5</version>
</dependency>
Define the ModelMapper bean in your Spring configuration
#Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
Assuming the following models based on the given ER diagram you have given
public class UserDto {
Integer userId;
String role;
String username;
String password;
boolean enabled;
...default and parameterized constructor
...getter and setter methods
}
public class ProductDto {
Integer productId;
String imageUrl;
String category;
int productPrice;
int productQuantity;
String productName;
String productDesc;
...default and parameterized constructor
...getter and setter methods
}
public class RatingDto {
#Id
Integer id;
int rating;
String review;
String ratingscol;
ProductDto productDto;
UserDto userDto;
...default and parameterized constructor
...getter and setter methods
}
You can retrieve the ratings of a product using product id along with the user details by using the following method
#Repository
public interface RatingRepository extends JpaRepository<Rating, Integer>{
List<Rating> findByProduct_ProductId(Integer productId);
}
Then mapping rating objects to DTO
RatingDto ratingDto = modelMapper.map(rating, RatingDto.class);
Now you can retrieve username as following
ratingsDto.getUserDto().getUserName()
The same way you can retrieve the ratings by userId and access product details

Adding a new field with default value in a collection in Spring Data MongoDB

I am adding a new boolean field in a collection by adding an attribute to a Java Class entity that is being used in the MongoRepository interface. However, the existing documents' new field is being initialised as null in the database. I want the new field's default value in existing documents to be set to false. How can this be done in Spring Data MongoDB?
Let say your version 1 Java entity was
#Document
Public Class Person {
#Id
Private String id;
private String firstName;
private String lastName;
.........
.........
And later you have introduced
#Document
Public Class Person {
#Id
Private String id;
private String firstName;
private String lastName;
private Boolean isAlive; //New Boolean attribute
.........
.........
In java the default value of an instance object is null and so a document in mongoDB with no value for isAlive will be defaulted to null. If you need the default value to be false you could do this
private Boolean isAlive = Boolean.FALSE;

How to write query method for sorting the results based on the field which is part of parent entity spring data jpa

In spring data JPA we can write query methods to execute query. I have two entities
class A {
#Id
#Column
private String id;
private String name;
#ManyToOne
#JoinColumn(name = "b_field")
private B b;
}
class B {
#Id
#KeyField
#Column
private String id;
private String b_field
}
I want to write a query method "findByNameOrderByb_field" i.e find all the rows having name as provided and order the results on the basis of class B's field i.e b_field. Writing above function is not returning ordered results. Is there any way I can write this orderby query method in spring boot.
public interface ARepository extends CrudRepository<A, String> {
List<A> findByNameOrderByb_field(String name);
}
the above function is not returning ordered results based on B's b_field.
To access properties of B you have to include the field name of B in the declaration of the query method.
public interface ARepository extends CrudRepository<A, String> {
List<A> findByNameOrderByb_b_field(String name);
}
More information how SpringData resolves nested Properties can be found under:
Query Property Expressions

Resources