Spring Data JPA aggregation group by period of time - mysql

at the moment I develop a small eCommerce App with Spring Boot and AngularJS. For my data-access layer I use Spring Data JPA with a MySQL-DB. My next step is, that I want to plot some statistics for specific products. For example: how did the review-ratings from a specific product develop over time. So I would like to specify a period of time (e.g. 01.2016 - 03.2016) and than formulate one query that returns 10 or 15 Points in time (within the range) with the average rating of the reviews in this period. So that i can plot a Chart from that.
I found ways with Spring Data to get the average for one period (Between x and y), but then I would have to make 10 queries to the database (for each dot). So I want to know, if it is possible to formulate a query with spring data that splits a time-period in a fixed number of sub-periods and gets the average of customer-ratings within each sub-period? If yes, how can I achieve that?
An excerpt of my Data Model Looks as follows:
#Entity
#Table(name = "product_placement")
public class ProductPlacement implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "product_placement_id")
private long id;
#Column(name = "title")
private String title;
...
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="productPlacements")
private Set<CustomerReview> customerReviews;
}
#Entity
#Table(name = "customer_review")
public class CustomerReview implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name = "customer_review_id")
private String reviewIdentifier;
...
#Column(name = "rating")
private Integer rating;
#Column(name = "dateOfCreation", nullable=true, unique=false)
private LocalDateTime dateOfCreation;
#JsonBackReference
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(
name = "review_to_product",
joinColumns = #JoinColumn(name = "customer_review_id"),
inverseJoinColumns = #JoinColumn(name = "product_placement_id")
)
private Set<ProductPlacement> productPlacements;
}
Thank you!

Related

Use same Entity multiple times in another Entity

I am implementing a Spring Boot server using JPA and Hibernate where there are 2 entities: Channel and Translation.
The Channel entity has two fields (nameTranslations and descriptionTranslations that should hold the name and description of a channel in 2 languages french and english) which are of type Translation as described as follow:
Class Channel
#Entity
#Table(name = "CHANNEL")
public class Channel {
#Id
#Column(name = "ID")
private String id;
#OneToOne(mappedBy = "channel", cascade = CascadeType.ALL)
private Translation nameTranslations;
#OneToOne(mappedBy = "channel", cascade = CascadeType.ALL)
private Translation descriptionTranslations;
}
and
Class Translation
#Entity()
#Table(name = "TRANSLATION")
public class Translation {
#Id
#Column(name = "ID")
private String id;
#Column(length = 1024)
private String en;
#Column(length = 1024)
private String fr;
}
My issue is: How can I implement the previously described logic so that there are 2 Translation fields in the Channel class? I have tried it so far using #OneToOne annotation, but it doesn't work.
I'm not sure what kind of mapping you are trying to achieve, but this will work:
#Entity
#Table(name = "CHANNEL")
public class Channel {
#Id
#Column(name = "ID")
private String id;
#OneToOne(cascade = CascadeType.ALL)
private Translation nameTranslations;
#OneToOne(cascade = CascadeType.ALL)
private Translation descriptionTranslations;
}
or, if you want the columns on the other entity table:
#Entity
#Table(name = "CHANNEL")
public class Channel {
#Id
#Column(name = "ID")
private String id;
#OneToOne(mapped="name", cascade = CascadeType.ALL)
private Translation nameTranslations;
#OneToOne(mapped="description", cascade = CascadeType.ALL)
private Translation descriptionTranslations;
}
#Entity
#Table(name = "TRANSLATION")
public class Translation {
#Id
#Column(name = "ID")
private String id;
#Column(length = 1024)
private String en;
#Column(length = 1024)
private String fr;
#OneToOne
private Channel name;
#OneToOne
private Channel description;
}
See the Hibernate ORM documentation for one-to-one associations.

Foreign Keys in Spring Boot (MySQL, Hibernate, JPA)

I am trying to write a RESTful API using Spring Boot and I am not able to figure out a way to map my relations in the database. I have a User and a Reports table. Each User can have multiple Reports, and a single report consists of "FROM USER" and "TO USER" columns to indicate who sent the report and to whom. My User ID is the primary key and for the Report table, I am generating REPORT ID as the primary key using AUTO INCREMENT. Here is my User model class -
#Entity
#Table (name = "user")
#EntityListeners(AuditingEntityListener.class)
public class User {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
private String email;
private String password;
#OneToMany(mappedBy = "user",cascade = CascadeType.ALL)
private List<Report> reportReceivedList;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Report> reportSentList;
/* Getters and setters ..... */
}
Here is my Report Model class -
#Entity
#Table (name = "report")
#EntityListeners(AuditingEntityListener.class)
public class Report {
#Id
#Column (name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne()
#JoinColumn(name = "from_user_id")
private Long fromUserId; //THIS SHOULD BE FROM "USER" TABLE
#ManyToOne()
#JoinColumn(referencedColumnName = "to_user_id")
private Long toUserId; //THIS SHOULD BE FROM "USER" TABLE
#Temporal(TemporalType.DATE)
#CreatedDate
private Date createdAt;
private String observation;
private String context;
//Other variables and getters and setters .....
}
Can someone please show me a way to correctly define this relationship. My current model doesn't work. Also, I want rows from REPORT class to be deleted as soon as a user is deleted. Thanks!
I finally fixed it by changing my User class as follows -
#OneToMany(cascade = CascadeType.ALL, targetEntity = Report.class)
#JoinColumn(name = "to_user_id")
private List<Report> reportReceivedList;
#OneToMany(cascade = CascadeType.ALL, targetEntity = Report.class)
#JoinColumn(name = "from_user_id")
private List<Report> reportSentList;
And by changing my Report class as -
#Column(name = "from_user_id")
private Long fromUserId;
#Column(name = "to_user_id")
private Long toUserId;

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column in 'field list' using Criteria and mapping annotation

i have criterias to access result by
First Hibernate Dao is
AnswerText answersText = questionManager.getAnswerTextByAnswerIdAndLanguageId(answers.getAnswerId(), 1L);
#Override
public AnswerText getAnswerTextByAnswerIdAndLanguageId(Number answerId,Number languageId) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(AnswerText.class);
criteria.add(Restrictions.eq("answer.answerId", answerId));
criteria.add(Restrictions.eq("languageId", languageId));
List<AnswerText> results = criteria.list();
return (results !=null && !results.isEmpty()? results.get(0): null);
}
Answers.java
#Entity
#Table(name = "ANSWERS")
#Cacheable
#JsonIgnoreProperties(ignoreUnknown = true)
public class Answer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ANSWER_ID")
private Long answerId;
#Column(name = "QUESTION_ID")
private Long questionId;
#Column(name = "DATE_CREATED")
private Timestamp dateCreated;
#Column(name = "CREATED_BY_ID")
private Long creatorId;
#Column(name = "DATE_MODIFIED")
private Timestamp dateModified;
#Column(name = "MODIFIED_BY_ID")
private Long modifierId;
#OneToMany(fetch = FetchType.EAGER,mappedBy = "answer" )
private Set<AnswerText> answerText = new HashSet<AnswerText>();
//getters and setters
AnswerText.java
#Entity
#Table(name = "ANSWERTEXT")
#Cacheable
#JsonIgnoreProperties(ignoreUnknown = true)
public class AnswerText {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ANSWER_TEXT_ID")
private Long answerTextId;
#ManyToOne
#JoinColumn(name="answerId", insertable=false, updatable=false,
nullable=false)
private Answer answer;
#Column(name = "ANSWER_TEXT")
private String answerText;
#Column(name = "LANGUAGE_ID")
private Long languageId;
//getters and setters
When i access the to fetch resultset, it shows below error
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'answertext2_.answerId' in 'field list'
Then i changed to below in
AnswerText.java
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ANSWER_ID", nullable = false)
private Answer answer;
Answers.java
#OneToMany(fetch = FetchType.EAGER,mappedBy = "answer" )
#Fetch(FetchMode.JOIN)
private Set<AnswerText> answerText = new HashSet<AnswerText>();
This produce no error But fetch results twice on calling
Second HibernateDao call is
List<Answer> answerList = questionManager.getAnswersByQuestionId(Long.parseLong("2"));
System.out.println("answerList :"+answerList1.size());
#Override
public ArrayList<Answer> getAnswersByQuestionId(Number questionId) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Answer.class);
criteria.add(Restrictions.eq("questionId", questionId));
ArrayList<Answer> answerList = (ArrayList) criteria.list();
return answerList;
}
Can Please anyone point me what is going wrong here. PLease help me.
You have done right changing the JoinColumn-name.
Your multiple results in my opinion is bound to:
FetchType.EAGER and the selection of
FetchMode JOIN As indicated you’ll have to worry about duplicated
results. On the other hand JOIN creates the least amount of queries.
In a high latency environment a single JOIN could be considerable
faster then multiple SELECTS. Keep in mind that joining too much data
could put a strain on the database.
from http://www.solidsyntax.be/2013/10/17/fetching-collections-hibernate/
With FetchMode.SELECT you would get the result like you want to have it.

#Formula and PostgreSQL

I' using Hibernate 5 with PostgreSQL. All is fine but I've a problem with the #Formula annotation.
I've this entity
public class MyImage implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Lob
private byte[] content;
private Boolean favorite;
#ManyToOne
#JoinColumn(name = "father_id", nullable = false, updatable = true, insertable = true)
private Father father;
and this
public class Father implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true,mappedBy = "father")
private Set<MyImage> images;
#Formula("(select ai.content from my_image ai where ai.father_id = id and ai.favorite = 1)")
private byte[] neededBytes;
With MySQL is working fine, but with PostgreSQL I've some SQL Grammar Exception. Testing the #Formula's query inside the SQL editor, seems to be that for PostgreSQL istead of use
ai.favorite = 1
I need to use
ai.favorite = TRUE
but even if I change this query, I always get an SQL Grammar Exception.
Can you help me?

Hibernate order by Id of child table

I have two tables as follows:
//TmCategory table
public class TmCategory implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#Column(name="CATEGORY_NAME")
private String categoryName;
#Column(name="OWNER_ID")
private BigInteger ownerId;
//bi-directional many-to-one association to TmCategoryRate
#OneToMany(mappedBy="tmCategory", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#javax.persistence.OrderBy("startDate ASC")
private Set<TmCategoryRate> tmCategoryRates;
//getters and setters
}
//TmCategoryRates Table
#Entity
#Table(name="tm_category_rates")
public class TmCategoryRate implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#Column(name="CREATED_BY")
private BigInteger createdBy;
#Column(name="CREATED_DATE")
private Timestamp createdDate;
#Column(name="END_DATE")
private Timestamp endDate;
#Column(name="RATE")
private Double rate;
#Column(name="RATE_TYPE")
private String rateType;
#Column(name="START_DATE")
private Timestamp startDate;
//bi-directional many-to-one association to TmCategory
#ManyToOne
#JoinColumn(name="CATEGORY_ID")
private TmCategory tmCategory;
//getters and setters.....
}
And here is the detached criteria am using to get the categories
DetachedCriteria criteria = DetachedCriteria.forClass(TmCategory.class);
criteria.add(Restrictions.eq("id", catId));
DetachedCriteria criteria1 =criteria.createCriteria("tmCategoryRates");
criteria1.addOrder(Order.asc("id"));
List<TmCategory> categories = getHibernateTemplate().findByCriteria(criteria);
Here I am trying to sort the tmCategoryRates in ascending order of their ID.
I am able to get category if there is at least one tmCategoryRates is available for this category. If there is no tmCategoryRates available then its returning null instead of returning category with tmCategoryRates.
If there may be no rates for the category you need a left join. It is not clear why you are using DetachedCriteria here, but see this example from the Hibernate docs
List cats = session.createCriteria( Cat.class )
.createAlias("mate", "mt",
Criteria.LEFT_JOIN,Restrictions.like("mt.name", "good%") )
.addOrder(Order.asc("mt.age"))
.list();
Hibernate 3.5 -- 16.4 Associations