JAX-RS return a collection of your custom object? - jpa

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

Related

How to filter by faculty name?

I want to implement lazy record loading on a Primefaces DataTable (version 7). I have two entities, one is called Faculties and the other is Careers, which are related. The datatable correctly shows the list of all the races (includes pagination and filtering), the problem I have is that I do not know how to filter the races by the name of a certain faculty, since I do not know how to include the join in the query that I leave then.
Could you guide me on how to solve it please?
Entity Faculties
public class Facultades implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idfacultad")
private Integer idfacultad;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "nombre")
private String nombre;
#Size(max = 20)
#Column(name = "abreviatura")
private String abreviatura;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "idfacultad")
private List<Carreras> carrerasList;}
Entity Carreras
public class Carreras implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idcarrera")
private Integer idcarrera;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 150)
#Column(name = "nombre")
private String nombre;
#Basic(optional = false)
#NotNull
#Column(name = "tipo")
private int tipo;
#JoinColumn(name = "idfacultad", referencedColumnName = "idfacultad")
#ManyToOne(optional = false)
private Facultades idfacultad;}
Query findByParams
public List<Carreras> findByParams(int start, int size, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Carreras> criteriaQuery = criteriaBuilder.createQuery(Carreras.class);
Root<Carreras> root = criteriaQuery.from(Carreras.class);
CriteriaQuery<Carreras> select = criteriaQuery.select(root);
Join<Carreras, Facultades> facultad = root.join("idfacultad");
if (sortField != null) {
criteriaQuery.orderBy(sortOrder == SortOrder.DESCENDING ? criteriaBuilder.asc(root.get(sortField)) : criteriaBuilder.desc(root.get(sortField)));
}
if (filters != null && filters.size() > 0) {
List<Predicate> predicados = new ArrayList<>();
filters.entrySet().forEach((entry) -> {
String key = entry.getKey();
Object val = entry.getValue();
if (!(val == null)) {
// Construimos la expresion con los predicados que si existan
Expression<String> expresion = root.get(key).as(String.class);
Predicate predicado = criteriaBuilder.like(criteriaBuilder.lower(expresion), "%" + val.toString().toLowerCase() + "%");
predicados.add(predicado);
}
});
if (predicados.size() > 0) {
criteriaQuery.where(criteriaBuilder.and(predicados.toArray(new Predicate[predicados.size()])));
}
}
// Creamos la consulta
TypedQuery<Carreras> consulta = em.createQuery(select);
consulta.setFirstResult(start);
consulta.setMaxResults(size);
return consulta.getResultList();
}
You need to manually check if the filter key equals the Facultades object, and in that case create a predicate on the joined expression that you have already created:
if (key.equals("Facultad")) {
expresion = facultad.get("nombre").as(String.class);
} else {
expresion = root.get(key).as(String.class);
}

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?

valid query creation using the combination of keywords(And,Or)

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);

Netbeans wizard Entity Classes from Database, not all tables mapped

I used this wizard to create entity classes from my database. Some tables have not been transformed into classes, but there are attributes that identify the relationships.
this is my db ERD (mysql)
and this is the user entity class (attributes)
#Entity
#Table(name = "user")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "User.findAll", query = "SELECT u FROM User u"),
#NamedQuery(name = "User.findByOid", query = "SELECT u FROM User u WHERE u.oid = :oid"),
#NamedQuery(name = "User.findByUsername", query = "SELECT u FROM User u WHERE u.username = :username"),
#NamedQuery(name = "User.findByPassword", query = "SELECT u FROM User u WHERE u.password = :password"),
#NamedQuery(name = "User.findByEmail", query = "SELECT u FROM User u WHERE u.email = :email"),
#NamedQuery(name = "User.findByAddress", query = "SELECT u FROM User u WHERE u.address = :address"),
#NamedQuery(name = "User.findBySince", query = "SELECT u FROM User u WHERE u.since = :since")})
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "oid")
private Integer oid;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 15)
#Column(name = "username")
private String username;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 15)
#Column(name = "password")
private String password;
// #Pattern(regexp="[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", message="Invalid email")//if the field contains email address consider using this annotation to enforce field validation
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 30)
#Column(name = "email")
private String email;
#Size(max = 50)
#Column(name = "address")
private String address;
#Basic(optional = false)
#NotNull
#Column(name = "since")
#Temporal(TemporalType.DATE)
private Date since;
#JoinTable(name = "favorite", joinColumns = {
#JoinColumn(name = "user_oid", referencedColumnName = "oid")}, inverseJoinColumns = {
#JoinColumn(name = "wheelchair_oid", referencedColumnName = "oid")})
#ManyToMany
private List<Wheelchair> wheelchairList;
#ManyToMany(mappedBy = "userList1")
private List<Wheelchair> wheelchairList1;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "senderOid")
private List<Comment> commentList;
#JoinColumn(name = "role_oid", referencedColumnName = "oid")
#ManyToOne(optional = false)
private Role roleOid;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "userOid")
private List<Orthopedy> orthopedyList;
public User() {
}
...
i can't understand something:
where is the OWN join table?
why i have userList1 and wheelchairList1? should it identifies OWN table? in this case i can rename it here or i have to rename it in some xml file?
why of
#OneToMany(cascade = CascadeType.ALL, mappedBy = "userOid")
private List<Orthopedy> orthopedyList;
?
it should be OneToOne...
moreover the "JSF from entities class" wizard creates CRUD operation to manage Users, how can i manage join tables? I need to write something in the controller like what?
can you please link me some resource where i can learn this?
thank you so much
While Creating Entities It Creates Classes For All Tables With Primary Key
But not for tables that have many to many relations . its managed by their parent classes it is maintained as a list.
This is my code for managing my many to many table of SubjectFaculty which has details of Faculty and Subjects
Assigning A Subject To Faculty
public void assignFacultyToSubject(String facultyUname, Integer subjectId) {
try {
Subject oSubject = em.find(Subject.class, subjectId);
Faculty oFaculty = em.find(Faculty.class, facultyUname);
College oCollege = em.find(College.class, oFaculty.getCollegeUname().getCollegeUname());
List<Faculty> lstFaculty = oSubject.getFacultyList();
List<Subject> lstSubject = oFaculty.getSubjectList();
if (!lstSubject.contains(oSubject)) {
lstFaculty.add(oFaculty);
lstSubject.add(oSubject);
oSubject.setFacultyList(lstFaculty);
oFaculty.setSubjectList(lstSubject);
em.merge(oSubject);
em.getEntityManagerFactory().getCache().evictAll();
} else {
System.out.println("Entry Already Found");
}
} catch (Exception e) {
System.out.println("Error :- " + e.getMessage());
}
}
Removing Subject And Faculty Details Form Many to Many Table
#Override
public void removeFacultySubject(String facultyUname, Integer subjectId) {
try {
Subject oSubject = em.find(Subject.class, subjectId);
Faculty oFaculty = em.find(Faculty.class, facultyUname);
List<Subject> lstSubject = oFaculty.getSubjectList();
List<Faculty> lsFaculty = oSubject.getFacultyList();
lstSubject.remove(oSubject);
lsFaculty.remove(oFaculty);
em.merge(oSubject);
} catch (Exception e) {
System.out.println("Error :- " + e.getMessage());
}
}

Group By in Java Persistence/JPQL

I have an Entity class and it has #ManyToOne relationships. I need to use GROUP BY as in SQL query.
I have written a JPQL but its not working. My code is :
#NamedQuery(name = "AssetDepModel.findByAssedId",
query = "SELECT dep FROM AssetDepModel dep "
+ "JOIN dep.faDetails fad "
+ "WHERE fad.assetId.assId = :assetId_passed "
+ "GROUP BY dep.faDetails,dep.faDetails.id,dep.fiscalModel.fyId,dep.depAmt,dep.depId,dep.depMethodId,dep.depRate,dep.depTypeId,dep.quarterId,dep.createdDt,dep.createdBy,dep.updatedDt,dep.updatedby "
+ "ORDER BY fad.id")
public class AssetDepModel implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
public static final String FIND_BY_ASSET_ID = "AssetDepModel.findByAssedId";
public static final String FIND_BY_DETAIL_ID = "AssetDepModel.findByDetailId";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "dep_id")
private int depId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "fiscal_id", referencedColumnName = "fy_id")
private FiscalYrModel fiscalModel;
#Column(name = "quarter_id")
private int quarterId;
#ManyToOne
#JoinColumn(referencedColumnName = "id", name = "fa_details_id")
private FADetailsModel faDetails;
#Column(name = "dep_type_id")
private int depTypeId;
#Column(name = "dep_method_id")
private int depMethodId;
#Column(name = "dep_rate")
private Double depRate;
#Column(name = "dep_amt")
private Double depAmt;
#Column(name = "created_dt")
#Temporal(TemporalType.TIMESTAMP)
private Date createdDt;
#Column(name = "created_by")
private int createdBy;
#Column(name = "updated_dt")
#Temporal(TemporalType.TIMESTAMP)
private Date updatedDt;
#Column(name = "updated_by")
private int updatedby;
I tried this code but while calling the JPQL it always gives error saying that objects in Select is not included in Group By clause.
I need to GROUP BY according to a foreign key field.
I get following error :
Internal Exception: com.microsoft.sqlserver.jdbc.SQLServerException: Column
'inv_asset_depreciation.fa_details_id' is invalid in the select list because
it is not contained in either an aggregate function or the GROUP BY clause.
Error Code: 8120
Call: SELECT t0.dep_id, t0.created_by, t0.created_dt, t0.dep_amt, t0.dep_method_id,
t0.dep_rate, t0.dep_type_id, t0.quarter_id, t0.updated_dt, t0.updated_by,
t0.fa_details_id, t0.fiscal_id FROM inv_asset_depreciation t0, fiscal_yr t2,
inv_fixed_asset_detail_mcg t1 WHERE ((t1.asset_id = ?) AND ((t1.id = t0.fa_details_id)
AND (t2.fy_id = t0.fiscal_id))) GROUP BY t1.id, t1.asset_given_name,
t1.brand_name_description, t1.created_by, t1.created_date,
t1.dispose_dt_en,t1.dispose_dt_np, t1.dispose_value, t1.req_form_no,
t1.start_use_dt_en,t1.start_use_dt_np,t1.update_count, t1.updated_by,
t1.updated_date, t1.asset_id,t1.dept_id, t1.status, t1.id,t2.fy_id, t0.dep_amt,
t0.dep_id, t0.dep_method_id,t0.dep_rate, t0.dep_type_id,t0.quarter_id,
t0.created_dt, t0.created_by,t0.updated_dt, t0.updated_by
ORDER BY t1.id
bind => [1 parameter bound]
Query: ReportQuery(name="AssetDepModel.findByAssedId" referenceClass=AssetDepModel
sql="SELECT t0.dep_id, t0.created_by, t0.created_dt, t0.dep_amt,
t0.dep_method_id,t0.dep_rate,t0.dep_type_id, t0.quarter_id, t0.updated_dt,
t0.updated_by, t0.fa_details_id,t0.fiscal_id FROM inv_asset_depreciation t0,
fiscal_yr t2, inv_fixed_asset_detail_mcg t1 WHERE ((t1.asset_id = ?)
AND ((t1.id = t0.fa_details_id) AND (t2.fy_id = t0.fiscal_id)))
GROUP BY t1.id, t1.asset_given_name, t1.brand_name_description,
t1.created_by,t1.created_date, t1.dispose_dt_en, t1.dispose_dt_np,
t1.dispose_value, t1.req_form_no, t1.start_use_dt_en, t1.start_use_dt_np,
t1.update_count, t1.updated_by, t1.updated_date,t1.asset_id, t1.dept_id,
t1.status, t1.id, t2.fy_id, t0.dep_amt, t0.dep_id, t0.dep_method_id,
t0.dep_rate, t0.dep_type_id, t0.quarter_id, t0.created_dt,
t0.created_by, t0.updated_dt,t0.updated_by ORDER BY t1.id")
I modified a little bit like this :
#SuppressWarnings("unchecked")
public List<Object> findByAssetIdForSaleWriteOff(int assetId){
Query query = getEntityManager().createQuery("SELECT fad.id,dep.depAmt FROM AssetDepModel dep "
+ "JOIN dep.faDetails fad "
+ "WHERE fad.assetId.assId = "+assetId+" "
+ "GROUP BY fad.id,dep.depAmt "
+ "ORDER BY fad.id",AssetDepModel.class);
return (List<Object>)query.getResultList();
}
List<Object> objList = assetDepEJB.findByAssetIdForSaleWriteOff(faObj.getAssId());
Double amountDepTillNow = 0.0;
int fadId = 0;
int i=0;
for (Iterator<Object> iterator3 = objList.iterator(); iterator3
.hasNext();) {
Object[] obj = (Object[]) iterator3
.next();
if (i>0) {
if (fadId != (Integer) obj[0]) {
break;
}
}
fadId = (Integer) obj[0];
amountDepTillNow += (Double)obj[1];
i++;
}
It worked for me but If there is another efficient way, PLEASE DO SUGGEST ME.