Spring-Boot | SqlResultSetMapping for just one attribute - spring

In our project we just get the ids from the study table. Do we need a SqlResultSetMapping or is it enough to just declare that we will get UUIDs from the query? When yes, how?
Mapping
#SqlResultSetMapping(name = "StudyMapping", classes = {
#ConstructorResult(targetClass = StudyId.class,
columns = {
#ColumnResult(name = "id", type = UUID.class)
}
)
})
Class for the mapping StudyId
#AllArgsConstructor
#Builder
#Getter
#Setter
public class StudyId {
private UUID id;
}
Query
SELECT DISTINCT id FROM Study;

Related

JPA JoinTable with additional columns

Spring Boot
Spring Data
JPA Hibernate
Came across a requirement where JPA ManyToMany relationship table with an extra column. Have looked at StackOverflow and found several questions related to same requirement. Most of the answers on the forums ask for EmbeddedId field with a composite primary key with two columns. I tried the solutions from the forums, here is the code snippet.
#Data
#Entity
#Table (name = "TABLE_A")
public class TableA {
#Id
#Column (name = "table_a_id")
private Integer id;
...
#OneToMany (mappedBy = "pk.tableA")
private List<TableABMapping> mappingTable;
}
#Data
#Entity
#Table (name = "TABLE_B")
public class TableB {
#Id
#Column (name = "table_b_id")
private Integer id;
...
#OneToMany (mappedBy = "pk.tableB")
private List<TableABMapping> mappingTable;
}
#Data
#Entity
#Table (name = "TABLE_A_TABLE_B_MAPPING")
public class TableABMapping implements Serializable {
#EmbeddedId
private MappingKey pk = new MappingKey();
#Column(name = "addon_field")
private Double additionalField;
#Transient
public TableA getTableA() {
return getPk().getTableA();
}
public void setTableA(TableA tableA) {
getPk().setTableA(tableA);
}
#Transient
public TableB getTableB() {
return getPk().getTableB();
}
public void setTableB(TableB tableB) {
getPk().setTableB(tableB);
}
// equals() & hashCode() method override
}
#Data
#Embeddable
public class MappingKey implements Serializable {
#ManyToOne
#JoinColumn(name = "table_a_id", referencedColumnName = "table_a_id")
private TableA tableA;
#ManyToOne
#JoinColumn(name = "table_b_id", referencedColumnName = "table_b_id")
private TableB tableB;
// No argument constructor, two arguments constructor.
// equals() & hashCode() method override
}
Trying save operation from service class like this:
for (TableB tabB : tableA.getTableB()) {
TableABMapping abMapping = new TableABMapping();
abMapping.setTableA(tableA);
abMapping.setProduct(tabB);
abMapping.setAdditionalField(tabB.getAddonField());
if (tableA.getMappingTable() == null) {
tableA.setMappingTable(new ArrayList<TableABMapping>());
}
tableA.getMappingTable().add(abMapping);
}
TableA ta = tableARepository.save(tableA);
System.out.println("TableA.save(): " + ta);
Getting this error on save operation.
Unable to find TableABMapping with id MappingKey(tableA = TableA( ... ), tableB = TableB ( ... ))
Both the entities have proper ids at the time of saving the entity. But still it throws this error. Where I am making mistake?

No converter found capable of converting from type AbstractJpaQueryTupleConverterTupleBackedMap to Custom Java POJO Class

Hi I am trying to read a list of values from a native Query in JPA .
My Repository Interface is
#Query(value = "SELECT E_MAIL AS email FROM USERS WHERE UID = ?1 ",nativeQuery = true )
public List<AuditPipeLineModel> getAuditPipeLine(#Param("uid") String uid);
My Model Class is
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class AuditPipeLineModel {
private String email;
}
Am getting an exception as
No converter found capable of converting from type
[org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to
type [AuditPipeLineModel]
What is the mistake i am doing ?
The Native Query and Model class is much bigger than this , i just avoided it to make it simple.
try this
#Query(value = "SELECT new package.towards.AuditPipeLineModel(E_MAIL) FROM USERS WHERE UID = ?1 ",nativeQuery = true )
public List<AuditPipeLineModel> getAuditPipeLine(#Param("uid") String uid);

Spring Boot JPA Save failing for Embedded Primary Key

I have struggled to make the save through JPA work. I've used a custom naming strategy for which I added this configuration in my application.yml:
spring:
jpa:
hibernate:
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
hbm2ddl:
auto: none
This is my entity:
#Data
#Entity
#Builder
#AllArgsConstructor
#Table(name = "Tour_Rating")
#NoArgsConstructor(access = AccessLevel.PROTECTED)
public class TourRating {
#EmbeddedId
private TourRatingPk ratingPk;
#Column(name = "score", nullable = false)
private int score;
#Column(name = "comment")
private String comment;
}
This is the embedded primary key:
#Data
#Builder
#Embeddable
#AllArgsConstructor
#NoArgsConstructor(access = AccessLevel.PROTECTED)
public class TourRatingPk implements Serializable {
#ManyToOne
private Tour tour;
#Column(insertable = false, updatable = false, nullable = false)
private int customerId;
}
This is the entity in the composite key class which is meant to join on the tourId variable:
#Data
#Entity
#Builder
#AllArgsConstructor
#Table(name = "Tour")
#NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Tour {
#Id
#Column(name = "tourId")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer tourId;
....
}
The whole thing falls apart within the controller when the save method is called, controller below:
#RestController
#RequiredArgsConstructor
#RequestMapping(path = "/tours/{tourId}/ratings")
public class TourRatingController {
private final TourRatingRepository ratingRepository;
private final TourService tourService;
#PostMapping
#ResponseStatus(CREATED)
public void createTourRating(#PathVariable(value = "tourId") int tourId,
#RequestBody #Validated RatingApi ratingApi) {
Tour tour = verifyTour(tourId);
TourRatingPk ratingPk = TourRatingPk.builder()
.tour(tour)
.customerId(ratingApi.getCustomerId())
.build();
TourRating tourRating = TourRating.builder()
.ratingPk(ratingPk)
.score(ratingApi.getScore())
.comment(ratingApi.getComment())
.build();
ratingRepository.save(tourRating);
}
#ResponseStatus(NOT_FOUND)
#ExceptionHandler(NoSuchElementException.class)
public String respondWith400(NoSuchElementException elementException) {
return elementException.getMessage();
}
private Tour verifyTour(int tourId) throws NoSuchElementException {
return toBusiness(tourService.retrieveTour(tourId), null);
}
}
This is the repository for the TourRating:
#RepositoryRestResource(exported = false)
public interface TourRatingRepository extends JpaRepository<TourRating, TourRatingPk> {
List<TourRating> findByRatingPkTourTourId(int tourId);
Optional<TourRating> findByRatingPkTourTourIdAndRatingPkCustomerId(int tourId, int customerId);
}
When it hits the call to "save", it throws this message:
Caused by: java.sql.SQLSyntaxErrorException: Unknown column 'tourrating0_.tour_tourId' in 'field list'
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120) ~[mysql-connector-java-8.0.23.jar:8.0.23]
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-java-8.0.23.jar:8.0.23]
I've read through quite a number of other StackOverflow topics which mostly deal with the find/retrieve side, but haven't found anything to do with how to deal with saving an entity which has an embedded primary key.
P.S: this is my request body JSON below:
{
"score" : 5,
"comment" : "It was great!",
"customerId" : 123
}
Flyway script for rating:
CREATE TABLE IF NOT EXISTS Tour_Rating(
tourId INT,
customerId INT,
score INT NOT NULL,
comment VARCHAR(2000),
FOREIGN KEY (tourId) REFERENCES Tour(tourId),
PRIMARY KEY(tourId, customerId),
UNIQUE KEY unique_rating (tourId, customerId)
);
This was an interesting issue which I had tried a few things only to discover, all I needed was the magic line in my embedded Primary key class below:
#Data
#Builder
#Embeddable
#AllArgsConstructor
#NoArgsConstructor(access = AccessLevel.PROTECTED)
public class TourRatingPk implements Serializable {
#ManyToOne
**#JoinColumn(name = "tourId", referencedColumnName = "tourId")**
private Tour tour;
#Column(insertable = false, updatable = false, nullable = false)
private int customerId;
}
This helped hibernate know where to find the column to reference! Also without the #JoinColumn annotation line I added in the class above, I updated this config in application.yml:
hbm2ddl:
auto: none
to
hbm2ddl:
auto: update
this made hibernate create a completely new column with the column name it expected to find in Tour_Rating table called ('tour_tourId') and, complained that I need to supply a default value for the 'tourId' column within Tour_Rating which was the column I expected it to populate anyway.
So, watch out for this guys.
Mehn, programming is a beauty honestly. lol

LOMBOK default field value doesn't work with ORIKA-MAPPER

My contract class
#JsonIgnoreProperties(ignoreUnknown = true)
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class PaginationRequest {
private String sortBy;
}
My service class
#JsonIgnoreProperties(ignoreUnknown = true)
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class PaginationRequest {
#Default private String sortBy = "publishDate";
}
After Orika-mapper converting I get sortBy with null value.
When user submit nothing, how can we have sortBy come with its default value?
I end up having my contract class added the default constructor with default field value:
public PaginationRequest() {
sortBy = "publishDate";
}
Because it can't help even I tried to have #Default private String sortBy = "publishDate"; with my contract field

Unique argument of column annotation is not considered

In the entity attribute I make it to be unique :
#Entity
#Table(name = "role")
public class Role {
#Id
#Column(unique=true)
private String role_code;
...
}
But at runtime when inserting a new record then no exception is raised , nor console ! Although database is correctly set as the role_code column is a varchar2 primary key :
#RequestMapping(value = "/save", method = RequestMethod.POST)
public ModelAndView save(#ModelAttribute("role_details") Role role) {
roleDao.saveOrUpdate(role);
return new ModelAndView("redirect:/adminrole/");
}
So how to enforce unique constraint at the entity level ?
Try:
#Entity
#Table(name = "role", indexes = {#Index(name = "some_index_name", columnList = "role_code", unique = true})
public class Role { ... }

Resources