How to add One to One relationship with an Embeddable - spring

Requirement:
To fetch the list of requests along with the requests feedback status.
What I'm doing now :
Fetch all the requests using JPQL query. Loop through each request and fetch status and set into response dto.
What I want to doing.
Fetch all the request along with the status using JPQl query
What I'm looking for :
How can I add one to one mapping for requests & status, so that I can fetch status.
Sample code
This is the MSREQUEST entity
#Entity
#Table(name = "MSREQUEST")
public class Request implements Serializable {
#Id
private long requestId;
#Column(name = "DESC")
private string desc;
//getter.. setter...tostring and hashcode
}
This is the status entity
#Entity
#Table(name="FEEDBACKSTATUS")
public class FeedbackStatus implements Serializable {
// composite-id key
#EmbeddedId
private RequestFeedBackId requestFeedbackKey = new RequestFeedBackId();
#Column(name="STATUS")
private Long status;
//getter.. setter...tostring and hashcode
}
This is the embeddable entity
#Embeddable
public class RequestFeedBackId implements Serializable {
#Column(name="REQUESTID")
private Long requestId;
#Column(name="FEEDBACKID")
private Long feedbackId;
}
Service
#Override
public List<MsaRequestSearchDto> searchMsaRequests(MsaRequestSearchDto msaRequestSearchDto)
throws MsaException, Exception {
List<MsaRequestSearchDto> msaRequestSearchDtoList = msaRequestRepoCustom.findMsaRequests(msaRequestSearchDto);
*// get feedback status loop thru and fetch status for each one. nee to avoid this
if(msaRequestSearchDtoList != null && msaRequestSearchDtoList.size() > 0){
// code to fetch dstatus
}*/
return msaRequestSearchDtoList;
}
JPQL query that Im using..
public String GET_MSA_REQUEST = "SELECT dsr FROM Request dsr WHERE 1=1";
E-R

Related

Got status 500 and message "Missing URI template variable 'rank'", whenever test HTTP POST request on postman

I got the error "Resolved [org.springframework.web.bind.MissingPathVariableException: Missing URI template variable 'rank' for method parameter of type Rank]" on eclipse console
And message: "Missing URI template variable 'rank' for method parameter of type Rank" with status "500" whenever try HTTP POST request
My RESTController code:
#RestController
#RequestMapping(path = "/comp")
public class RankController {
#PostMapping(path = "/rank")
ResponseEntity<Rank> createRank(#Valid #PathVariable Rank rank) throws URISyntaxException{
Rank result = rankRepository.save(rank);
return ResponseEntity.created(new URI("/comp/rank" + result.getId())).body(result);
}
}
My Rank entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "RANK_TBL")
public class Rank {
#Id
private Long id;
private String name;
#ManyToOne(cascade = CascadeType.PERSIST)
private Employee employee;
}
My Employee entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "EMPLOYEE_TBL")
public class Employee {
#Id
private Long id;
private String name;
private String email;
#OneToMany
private Set<Rank> Rank;
}
Change #PathVariable with #RequestBody
Here you are making a request to save the entity and you should pass the payload as #RequestBody in JSON format. From postman you may use raw type and select the JSON type.
Ideal way is to use #RequestBody whenever we are creating or updating the records which requires the object to passed with POST and PUT methods. For methods which retrieves the records based on Id or some parameters you may use #PathVariable
You may explore more about the annotations here

Spring Data integration for ArangoDb gives back empty result list on queries

When I use queries from method names with ArangoDb and Spring Data integration I always get empty lists.
What is the problem in the way I use?
This is an example.
These are the Entities:
Authorization:
#Document("authorizations")
#Data // (Lombok)
public class Authorization {
#Id
private String id;
private String caption;
#Relations(edges = com.picktur.server.relations.UserAuthorized.class, lazy = true)
private User user;
}
User:
#Document("users")
#Data #NoArgsConstructor // (Lombok)
public class User {
#Id
private String id;
private String username;
#Relations(edges = com.picktur.server.relations.UserAuthorized.class, lazy = true)
private Collection<Authorization> authorizations;
}
Authorization Repository:
public interface AuthorizationRepo extends ArangoRepository<Authorization, String> {
Iterable<Authorization> findAllByUser(User user);
}
Edge between User and Authorization:
#Edge
#Data
public class UserAuthorized {
#Id
private String id;
#From
private User user;
#To
private Authorization authorization;
public UserAuthorized( User user, Authorization authorization) {
this.authorizedPhoto = user;
this.authorization = authorization;
}
}
Repository for UserAuthorized Egde:
public interface UserAuthorizedRepo extends ArangoRepository<UserAuthorized, String> {
}
Data Persistency logic:
User user = get_user_from_security_context();
Authorization authorization = new Authorization();
authorization.setUser(user);
...
authorization = authorizationRepo.save(authorization);
UserAuthorized userAuthorized = new UserAuthorized(user, authorization);
userAuthorizedRepo.save(userAuthorized);
Query that has empty result:
Iterable<Authorization> authorizations = authorizationRepo.findAllByUser(user);
All the documents and edges exist in DB but the result is empty.
Query derivation generates AQL query on document fields, eg. in case of findAllByUser it performs an AQL query like:
FOR a IN authorizations FILTER a.user == #user RETURN a
which obviously returns an empty array.
You can check the generated query enabling debug log level globally in your logback.xml.
According to your data model, to fetch all the authorizations of a given user you should perform something like this:
User user = userRepo.findById(userId).get();
Iterable<Authorization> authorizations = user.getAuthorizations();

Fetch List Using DTO projections using a Constructor Expression and JPQL

Perform a search on DisabScreenRequest and fetch its child details also. Using DTO projections using a Constructor Expression and JPQL.
The parent entity with a child table.
#Entity
#Table(name = "SCREEN_REQUEST")
public class DisabScreenRequest implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private long requestId;
#Column(name = "CIVILID")
private Long civilId;
#ManyToMany()
#JoinTable(name = "_DISAB_SCREEN_REQ_DETAILS", joinColumns = {
#JoinColumn(name = "REQUEST_ID") }, inverseJoinColumns = { #JoinColumn(name = "DISABILTY_TYPE_ID") })
private Set<DisabMaster> disabilities = new HashSet<DisabMaster>();
public DisabScreenRequest() {
}
}
This is the disability table.
#Entity
#Table(name="DISAB_MASTER")
#Immutable
public class DisabMaster implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="DIS_TYPE_ID")
private long disabilityTypeId;
#Column(name="DIS_TYPE_DESC")
private String disTypeDesc;
public DisabMaster() {
super();
}
}
Had to fetch all the requests along with the disability for each request.
Search DTO(using this I had other joins to add other than one mentioned here).
public class RequestSearchDto {
private long requestId;
private Long civilId;
private Set<DisabMaster> disabilities;
public RequestSearchDto() {
super();
}
public RequestSearchDto(long requestId, Long civilId) {
super();
this.requestId = requestId;
this.civilId = civilId;
}
public RequestSearchDto(long requestId, Long civilId, Set<DisabMaster> disabilities) {
super();
this.requestId = requestId;
this.civilId = civilId;
this.disabilities = disabilities;
}
}
This is my JPQL query
public interface ReposJPQL {
public String GET__REQUEST = "SELECT DISTINCT new org.test.RequestSearchDto "
+ "(dsr.requestId, dsr.civilId, dsr.disabilities)"
+ " FROM DisabScreenRequest dsr WHERE 1=1 ";
}
This will get an
org.hibernate.exception.SQLGrammarException: could not extract ResultSet.
What Iam I doing wrong here, how can I fetch the child table data ?
Let me know if you need any info
Stack trace :
Caused by: java.sql.SQLException: ORA-00936: missing expression
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:113)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:288)
at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:754)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:219)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:813)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1051)
at oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStatement.java:854)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1156)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3415)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3460)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:76)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:60)
If you need to fetch parent entity with a collection of its nested child entities you can use this simple approach using #EntityGraph annotation or JPQL with join fetch:
#Entity
public class Parent {
//...
#OneToMany
private List<Child> children;
}
#Entity
public class Child {
//...
}
interface ParentRepo extends JpaRepository<Parent, Integer> {
// with #EntityGraph
#EntityGraph(attributePaths = "children")
#Override
List<Parent> findAll();
// or manually
#Query("select distinct p from Parent p left join fetch p.children")
List<Parent> findWithQuery();
}
Note to use distinct in your query to avoid duplicate records.
Example: duplicate-parent-entities
More info: DATAJPA-1299
AFAIK, you can't use constructor expression which take a Collection.
See the JPA 2.2 Spec, section 4.14 BNF, read about the constructor expression:
constructor_expression ::=
NEW constructor_name ( constructor_item {, constructor_item}* )
constructor_item ::=
single_valued_path_expression |
scalar_expression |
aggregate_expression |
identification_variable
This is a perfect use case for Blaze-Persistence Entity Views.
I created the library 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.
A mapping for your model could look as simple as the following
#EntityView(DisabScreenRequest.class)
interface RequestSearchDto extends Serializable {
#IdMapping
long getRequestId();
Long getCivilId();
Set<DisabMaster> getDisabilities();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
RequestSearchDtodto = entityViewManager.find(entityManager, RequestSearchDto.class, id);
But the Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/1.4/entity-view/manual/en_US/#spring-data-features

Spring Data JPA findOne returns null

I'm using Spring Data JPA and I'm facing a very weird issue with findOne method which is returning null even though the row is present in DB.
I have a consumer thread which takes an id from a queue and tries to fetch the entity from DB which always returns null, however if I pause thread (by putting a breakpoint before method call) then it fetches the entity from DB but returns null in normal execution of program, I know it sounds weird with breakpoint stuff but it is what it is, may be I'm missing something. My code looks like below:-
if (id > 0) {
employee = employeeService.get(id);
if (employee == null) {
logger.error(String.format("No employee found for id : %d",
id));
return;
}
I'm not using any transaction in "employeeService" as it is not required as it is a read operation.
My service looks like
public Employee get(long id) {
return employeeDao.findOne(id);
}
And my model looks like:-
#Entity
#Table(name = "employee")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Employee implements Serializable {
private static final long serialVersionUID = 1681182382236322985L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "name")
private String name;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "emplopyee_id")
#Fetch(FetchMode.SELECT)
private List<Address> addresses;
// getter/setter and few fields have been omitted
}
Can somebody point me where I'm mistaking.
The Spring 4.2 way to do this would be to introduce a #TransactionEventListener annotated method on a spring component to handle the callback. You then simply need to publish an event and let the event framework do its thing:
// Spring component that handles repository interactions
#Component
public class ProducerService implements ApplicationContextAware {
private ApplicationContext applicationContext;
#Transactional
public void doSomeThingAwesome(String data) {
MyAwesome awesome = new MyAwesome( data );
myAwesomeRepository.save( awesome );
applicationContext.publishEvent( new MyAwesomeSaved( awesome.getId() ) );
}
}
// Spring component that handles the AFTER_COMMIT transaction callback
// This component only fires when a MyAwesomeSaved event is published and
// the associated transaction it is published in commits successfully.
#Component
public class QueueIdentifierHandler {
#TransactionalEventListener
public void onMyAwesomeSaved(MyAwesomeSaved event) {
Long entityId = event.getId();
// post the entityId to your queue now
}
}

retrieving data from database as json in spring boot

I have a MySQL database and I want to retrieve some data as json.
And I have an entity Offre wich has #OneToMany relation with the AssociationCandidatOffre entity.
and I have an api which calles this method in my repository :
offreRepository.findAll();
Offre entity :
#Entity
public class Offre implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "CODE_OFFRE")
private Long codeOffre;
private String titre;
#OneToMany(mappedBy = "offre")
private Collection<AssociationCandidatOffre> associationCandidatOffres;
public Collection<AssociationCandidatOffre> getAssociationCandidatOffres() {
return associationCandidatOffres;
}
public void setAssociationCandidatOffres(Collection<AssociationCandidatOffre> associationCandidatOffres) {
this.associationCandidatOffres = associationCandidatOffres;
}
//... getters/setters
}
AssociationCandidatOffre entity :
#Entity
public class AssociationCandidatOffre implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long idAssociation;
private String lettreMotivation;
private String tarifJournalier;
private Date dateDisponibilite;
#ManyToOne
private Candidat candidat;
#ManyToOne
private Offre offre;
#JsonIgnore
#XmlTransient
public Candidat getCandidat() {
return candidat;
}
#JsonSetter
public void setCandidat(Candidat candidat) {
this.candidat = candidat;
}
#JsonIgnore
#XmlTransient
public Offre getOffre() {
return offre;
}
#JsonSetter
public void setOffre(Offre offre) {
this.offre = offre;
}
//... getters/setters
}
the problem is when I call the api /offres to return me a json object I get this error message instead :
Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: could not extract ResultSet (through reference chain: java.util.ArrayList[0]->com.***.Rekrute.entities.Offre["associationCandidatOffres"]);
nested exception is com.fasterxml.jackson.databind.JsonMappingException: could not extract ResultSet (through reference chain: java.util.ArrayList[0]->com.***.Rekrute.entities.Offre["associationCandidatOffres"])
when I use #JsonIgnore in the getAssocationCandidatOffres I dont get any errors but I want that association in the json result as well.
Normally, this shouldn't generate any error since I have #JsonIgnore in the other side of the relation which is getOffre().
how can I solve this problem ?
You can't convert a bidirectional relation of an enitity to JSON.
You get an endless loop.
JSON-Parser starts with the entity Offer and reads the associated AssociationCandidatOffre via getAssociationCandidatOffres(). For every AssociationCandidatOffre the JSON-Parser read getOffre() and starts again. The parser don't know when he must end.

Resources