valid query creation using the combination of keywords(And,Or) - spring-data-jpa

Below is my entity
#Entity
#Table(name = "xxxxx")
public class xxxx implements Serializable {
private static final long serialVersionUID = -1935611638367876605L;
#Column(name = "PHONE1")
private long phone1;
#Column(name = "PHONE2")
private long phone2;
#Column(name = "SSN")
private String ssn;
}
My requirement is a combination of SSN && (phone1 || phone2)
is this a valid query creation using the keywords(And ,Or)
findBySSNAndPhone1Orphone2?

#Query("select x from Xxx x where x.ssn = ?1 and (x.phone1 = ?2 or x.phone2 = ?3)")
List<Xxx> findBySsnAndPhone1OrPhone2(String ssn, String phone1, String phone2);

Related

JPA Repository Query on additional table #ManytoMany

I want to do select like this in my jpa spring repository
SELECT sicknes_id, count(symptomp_id) as ilosc FROM symptomp_sicknes where symptomp_id IN (1,2) group by sicknes_id Order by ilosc DESC;
My enitity
#Entity
#Table(name = "symptomp")
public class Symptomp {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "symptomp_id")
private Long symptomp_id;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#ManyToMany(cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH}, fetch = FetchType.LAZY)
#JoinTable(name = "symptomp_sicknes",joinColumns = #JoinColumn(name = "symptomp_id"),inverseJoinColumns = #JoinColumn(name = "sicknes_id"))
private Set<Sicknes> sicknes = new HashSet<>();
#Entity
#Table(name = "sicknes")
public class Sicknes {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "sicknes_id")
private Long sicknes_id;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#ManyToOne(cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH}, fetch = FetchType.LAZY)
#JoinColumn(name = "speciesId")
private Species species;
My Symptomp repository:
public interface SymptompRepository extends JpaRepository<Symptomp, Long> {
#Query("select p from Symptomp p where name like ?1%")
public List<Symptomp> findAllBySymptompName(String symptomp);
public Symptomp findByName(String symptomp);
public List<Symptomp> findByNameIn(List<String> list);
Integer countDistinctSymptompByName(String id);
}
How I can create this select in my JPA repository?
I try get value like in select but i got error mapping bean.
You can get query result as List<Object[]> using nativeQuery=true parameter
#Query("SELECT sicknes_id, count(symptomp_id) as ilosc FROM symptomp_sicknes where symptomp_id IN (1,2) group by sicknes_id Order by ilosc DESC", nativeQuery=true)
List<Object[]> getQueryResult();
Other option is to create dto class with appropriate constructor
public class QueryResultDto {
Long sicknesId;
Long count;
public QueryResultDto(Long sicknesId, Long count) {
this.sicknesId = sicknesId;
this.count = count;
}
}
Then using JPQL
#Query("select new yourproject.dtopath.QueryResultDto(...")
List<QueryResultDto> getQueryResult(#Param("symptompIds") List<Long> symptompIds);
If you want to avoid a native Query the best way is to create an Entity for that JoinTable. Then you can query it easily. Additional benefit if this is that if in future a requirement will pop up that you have to store additional attributes in that relation you will have the Entity already there to do that easily.

java.lang.NullPointerException: while filtering data using QueryDsl

I am using Spring data jpa for creating service. In following code I am using Querydsl for implementing search filter on grid. But for building name I am not able to filter the grid. I am getting
java.lang.NullPointerException: null.
For grid data is coming from multiple tables. I am not using joining for that. I mapped models classes with each other
#Service
public class RoomTransferService {
#Autowired
RoomTransferRepository roomTransferRepo;
#PersistenceContext
EntityManager em;
public List<RoomTransfer> findRoomTransfer(String sStatus, String sBuildName, String deptFrom, String deptTo) {
QRoomTransfer roomTransfer = QRoomTransfer.roomTransfer;
JPAQuery<RoomTransfer> query = new JPAQuery<RoomTransfer>(em);
query.from(roomTransfer);
// filter the details
if (sStatus != null) {
query.where(roomTransfer.sStatus.eq(sStatus));
}
// not filtering
if(sBuildName !=null) {
query.where(roomTransfer.roomDeptMap.room.building.sBuildName.eq(sBuildName));
}
List<RoomTransfer> QueryResultRoomTramsfer=query.fetch();
Return QueryResultRoomTramsfer;
Room class
#Entity
#Table(name = "room")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Room implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "room_seq_generator")
#SequenceGenerator(name = "room_seq_generator", sequenceName = "room_seq")
#Column(name = "nroom_id")
public Integer nRoomId;
#Column(name = "ncampus_id")
public Integer nCampusId;
#Column(name = "nbuild_id")
public Integer nBuildId;
#Column(name = "ninst_id")
public Integer nInstId;
#Column(name = "sfloor")
public String sFloor;
#Column(name = "sroom_number")
public String sRoomNumber;
#Column(name = "sroom_desc")
public String sRoomDesc;
#Column(name = "scomments")
public String sComments;
#Column(name = "daccepted_date")
public Timestamp dAcceptedDate;
#Column(name = "ssurveyor")
public String sSurveyor;
#Column(name = "narea")
public Integer nArea;
#Column(name = "ncrt_code_id")
public Integer nCRTCodeId;
#Column(name = "ncmn_room_bln")
public Integer nCMNRoomBln;
#Column(name = "nunvalidated_bln")
public Integer nUnvalidatedBln;
#Column(name = "sbfr_field")
public String sBfrField;
#Column(name = "ntemp_room_id")
public Integer nTempRoomId;
#Column(name = "bis_active")
public Boolean bIsActive;
#Column(name = "bis_jointuse")
public Boolean bIsJointuse;
#Column(name = "sstations_desc")
public String sStationsDesc;
#Column(name = "ddeleted_on")
public Timestamp dDeletedOn;
#Column(name = "ndeleted_by")
public Integer nDeletedBy;
#Column(name = "bis_incluster")
public Boolean bIsIncluster;
#Column(name = "bis_service_center_activity")
public Boolean bisServiceCenterActivity;
#Column(name = "service_center_comments")
public String serviceCenterComments;
#ManyToOne(optional = true)
#JoinColumn(name = "nbuild_id", insertable = false, updatable = false)
public Building building;
The NPE that you get is probably related to the limitation of QueryDsl where you cannot exceed four levels.
Your code exceeds four levels.
roomTransfer.roomDeptMap.room.building.sBuildName
You can read more on official documentation or related stackoverflow's question.
In the first link there is a solution to overcome this issue using QueryInit annotation.
If you do not want to alter your entity class you can perform a join (if possible) with an alias for the first 2 or 3 levels and then use this alias to complete the query.

Load tables only with some specific conditions (#Where)

What I'm trying to do is to load only promotions with promotion.enabled=1 AND PromotionType.enabled=1.
I tried to add the #Where annotation in both tables but when I set promotionType, enabled to 0 I´m getting an error.
On the other hand, I also tried to add the #WhereJoinTable clause to promotionType but I'm not getting the expected result. Any help?
The first one:
#Entity
#Table(name = "HOTEL_PROMOTION")
#Where(clause = "enabled=1")
public class Promotion implements Serializable {
private static final long serialVersionUID = 257070400893576505L;
#Id
#Column(name = "PROMOTION_ID")
private Long id;
#Column(name = "CODE")
private String code;
#Column(name = "NAME")
private String name;
#Column(name = "PRIORITY")
private Long priority;
#ManyToOne
#JoinColumn(name = "PROMOTION_TYPE_ID")
#WhereJoinTable(clause = "enabled=1")
private PromotionType promotionType;
#Column(name = "ENABLED")
private Boolean enabled;
}
The second one:
#Entity
#Table(name = "HOTEL_PROMOTION_TYPE")
public class PromotionType implements Serializable {
private static final long serialVersionUID = -8359165117733458987L;
#Id
#Column(name = "PROMOTION_TYPE_ID")
private Long id;
#Column(name = "CODE")
private String code;
#Column(name = "NAME")
private String name;
#Column(name = "STYLE")
private String style;
#Column(name = "ENABLED")
private Boolean enabled;
}

Returning complex objects from Spring Data #Query

I'm writing a Questionnaire application (Java, Spring Boot, SQL) and I have a working query for returning the count of each answer in the database for specified questionnaire:
#Query(value = "SELECT new org.project.domain.AnswerCount(a.value, count(a)) FROM "
+ "Answer a WHERE a.questionnaire = :questionnaire GROUP BY a.value")
List<AnswerCount> findAnswerCountByQuestionnair(#Param("questionnaire") Questionnaire questionnaire);
Now what I would like to do is to group these AnswerCounts by what question they are answers to and store that in a list of QuestionResponseData objects. I could do it in Java code by some stream grouping methods, but I would prefer to do it directly in the query for speed.
Is that even possible, and what would be the best way to do that?
Here are the relevant parts of the models:
public class AnswerCount {
private String answer;
private long count;
}
.
public class QuestionResponseData {
private String question;
private String type;
private List<AnswerCount> answers;
}
.
/**
* A Answer.
*/
#Entity
#Table(name = "answer")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Document(indexName = "answer")
public class Answer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#NotNull
#Column(name = "jhi_value", nullable = false)
private String value;
#ManyToOne
private Question question;
#ManyToOne
private Respondant respondant;
#ManyToOne
private Questionnaire questionnaire;
}
.
/**
* A Question.
*/
#Entity
#Table(name = "question")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Document(indexName = "question")
public class Question implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#NotNull
#Column(name = "text", nullable = false)
private String text;
#Enumerated(EnumType.STRING)
#Column(name = "jhi_type")
private QuestionType type;
#OneToMany(mappedBy = "question")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Answer> answers = new HashSet<>();
#ManyToMany(mappedBy = "questions")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Questionnaire> questionnaires = new HashSet<>();
}
I'm thinking something similar to this:
#Query(value = "SELECT new QuestionResponseData(q.text, q.type, answers) FROM "
+ "(SELECT new org.project.domain.AnswerCount(a.value, count(a)) as answerCount FROM "
+ "Answer a WHERE a.questionnaire = :questionnaire GROUP BY a.value") answers, "
+ "Question q WHERE answers.answerCount.question = q "
+ "GROUP BY answerCount.question")
but that obviously doesn't work...
Is it possible?

JAX-RS return a collection of your custom object?

I have a webservice that uses JAX-RS, JPA and JAXB. I've writen a method that should return a collection of objects from my database. This doesn't happen though. It only return a single item.
My method:
#GET
#Produces(MediaType.APPLICATION_XML)
#Path("findMeasurementsByRunID/{runID}")
public List<Measurement> getMeasurementByRunId(#PathParam("runID") int runID) {
List<Measurement> results = null;
Query query = emf.createEntityManager().createNamedQuery(
"findMeasurementsByRunID");
query.setParameter("runid", runID);
results = query.getResultList();
return results;
}
My Entity-class:
#Entity
#NamedQueries({
#NamedQuery(name = "findMeasurementsByRunID", query = "SELECT m "
+ "FROM Measurement m "
+ "WHERE m.runID = :runid"),
#NamedQuery(name = "findMeasurementsByRunIDPosition", query = "SELECT m "
+ "FROM Measurement m "
+ "WHERE m.runID = :runid AND "
+ "m.position = :position") })
#XmlRootElement
#XmlType(propOrder = { "runID", "rack", "position", "completionStatus",
"countingTime", "cr51Counts", "cr51CPM", "cr51Error",
"measurementDateTime", "protocolID", "protocolName" })
public class Measurement implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#AttributeOverrides({
#AttributeOverride(name = "runID", column = #Column(name = "RunID")),
#AttributeOverride(name = "position", column = #Column(name = "Position")) })
#Column(name = "RunID")
private int runID;
#Column(name = "Rack")
private int rack;
#Column(name = "Position")
private int position;
#Column(name = "Completionstatus")
private int completionStatus;
#Column(name = "CountingTime")
private double countingTime;
#Column(name = "Cr51Counts")
private double cr51Counts;
#Column(name = "Cr51CPM")
private double cr51CPM;
#Column(name = "Cr51Error")
private double cr51Error;
#Column(name = "MeasurementDateTime")
#Temporal(TemporalType.TIMESTAMP)
private Date measurementDateTime;
#Column(name = "ProtocolID")
private int protocolID;
#Column(name = "ProtocolName")
private String protocolName;
public Measurement() {
}
// Getters and Setters...
}
If I call the service it only returns the first item from the query as xml not the whole collection.
Output:
<measurements>
<measurement>
<runID>418</runID>
<rack>57</rack>
<position>1</position>
<completionStatus>0</completionStatus>
<countingTime>3599.97</countingTime>
<cr51Counts>2225.53</cr51Counts>
<cr51CPM>5.11</cr51CPM>
<cr51Error>44.26</cr51Error>
<measurementDateTime>2012-12-14T14:08:37.0</measurementDateTime>
<protocolID>3</protocolID>
<protocolName>Cr-51 GFR (almindelig blodproever)</protocolName>
</measurement>
</measurements>
How can I make the service return the whole collection of measurements and not just one item?
My data:
So you execute some query "findMeasurementsByRunID" which restricts it to a particular "runId" and you don't understand why you only get 1 Measurement object? Update your query to remove/change the filter so that it allows multiples