Hibernate generates unwanted aliases when using #Formula annotation - java

When I give to the #Formula annotation this piece of code :
#Formula("(SELECT SUM(commission.montant) FROM commission, affaire)")
private Double totalCommissionsMCourant;
Hibernates executes this SQL request :
[...,(SELECT SUM(commission.montant) FROM commission, a1_0.affaire) ...]
As you can see, the "FROM commission, affaire" turns into "FROM commission, a1_0.affaire", which makes the SQL request invalid.
Disclaimer : I know that having this type of calculated field here does not make sense but this is a simplified version of what I'd want to have.
Do you have any idea on how to prevent this problem from happening ?
Here is part of the Entity's code :
#Entity(name = "Apporteur")
#Table(name = "apporteur")
public class ApporteurEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Formula("(SELECT SUM(commission.montant) FROM commission, affaire)")
private Double totalCommissionsMCourant;
}
Hibernate version : 6.0.0

Related

Hibernate ignoring discriminator column - always using 'dtype'

I have a strange situation in my SINGLE_TAB inheritance Hibernate config whereby the #DiscriminatorColumn seems to be ignored and the query is always defaulting back to the 'dtype' column. It's like the behaviour I would see when I had not included the annotation at all (the default column name being 'dtype').
Base entity:
#Entity
#Table(name = "post")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(columnDefinition = "post_type", discriminatorType = DiscriminatorType.STRING)
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(name = "title")
private String title;
#Column(name = "body")
private String body;
#NotNull
#Column(name = "post_type", insertable = false, updatable = false)
private String postType;
// other simple columns
// ommit getters/setters + hashcode etc
}
Subclass entity:
#Entity
#DiscriminatorValue(value = "EVENT")
public class Event extends Post {
// ommitted basic methods, no extra config
}
I also need access to the discriminator value itself within each object (the postType field). I still have the same behaviour even if I remove it so it doesn't seem to be the cause.
When I try to do a query on the subclass through a JPA repository:
public interface EventRepository extends JpaRepository<Event, Integer> {
List<Event> findAll();
}
Hibernate generates the query:
select post0_.id as id2_4_, post0_.bodyl as body_bod3_4_, post0_.title as title12_4_
from post post0_
where post0_.dtype='EVENT'
which of course generates an error as 'dtype' doesn't exist in the table.
The strange thing is that if I use #DiscriminatorFormula("post_type") on the Post entity instead, everything seems to work. It is however slower so I would prefer to use the #DiscriminatorColumn as it should fit my needs exactly.
I am using Hibernate 5.2.10-FINAL and Spring Data JPA 1.11.4 (or generally the latest of hopefully everything).
Any ideas on what could be causing this?
I'm think you have this problem because you specified wrong parameter of #DiscriminatorColumn anotation, you should use name instead of columnDefinition.

Hibernate - org.hibernate.QueryException: could not resolve property:

I have a class DocMovement like this :
#Entity
#Table(name = "DOC_MVMNT")
public class DocMovement {
#Id
#GeneratedValue
#Column(name = "MVMNT_ID")
private int mvmnt_id;
#ManyToOne
#JoinColumn(name = "BARCODE")
public DocMaster docMaster;
// other fields and getters setters
}
The DocMaster class is something like this :
#Entity
#Table(name="DOC_MASTER")
public class DocMaster {
#Id
#NotNull
#Column(name = "BARCODE")
private String barcode;
#Column(name = "DOC_NO")
private String docNo ;
#Column(name="DOC_TYPE")
private String docType;
#Column(name="STATUS")
private String status;
// other fields and getters setters
}
When I am trying to run following code :
Criteria criteria = session.createCriteria(DocMovement.class,"documentMovement");
criteria.add(Restrictions.eq("documentMovement.recipientDetail.empId", empId));
criteria.add(Restrictions.eq("documentMovement.isCurrent", true));
criteria.add(Restrictions.ne("documentMovement.docMaster.status",FMSConstants.CLOSED_STATUS));
criteria.add(Restrictions.ne("documentMovement.docMaster.status",FMSConstants.DISPOSED_STATUS));
List<DocMovement> documentsHeld = (List<DocMovement>) criteria.list();
then I get the following exception :
[org.hibernate.QueryException: could not resolve property:
docMaster.status of: com.fms.persistence.DocMovement] with root cause
org.hibernate.QueryException: could not resolve property:
docMaster.status of: com.fms.persistence.DocMovement
there are other cases where I try to make query using criteria as shown above, the query runs fine, but I am unable to understand what am I doing wrong in this case. I have tried using eager fetch too, earlier I was not using an alias, so I tried using an alias too.
Please help me solve the issue !!!
Try adding alias :
criteria.createAlias("documentMovement.docMaster", "docMaster")
And later call
criteria.add(Restrictions.ne("docMaster.status",FMSConstants.CLOSED_STATUS));
You have to add an alias to docMaster first
I think that it's the comparaison with the enums that are not correct. You are trying to compare an enum with a String. This line seems wrong:
criteria.add(Restrictions.ne("documentMovement.docMaster.status",FMSConstants.CLOSED_STATUS));
Since documentMovement.docMaster.status is defined as a String, maybe try:
criteria.add(Restrictions.ne("documentMovement.docMaster.status",FMSConstants.CLOSED_STATUS.toString()));
criteria.add(Restrictions.ne("documentMovement.docMaster.status",FMSConstants.DISPOSED_STATUS.toString()));

Batch Fetching inside a normal find operation in EclipseLink

I would like to use the
#QueryHint(name=QueryHints.BATCH, value="pi.jrnls")
annotation together with the primary key #Id lookups.
Where do I put the annotation? It looks like I can only put it inside a #NamedQuery. But the default pk lookup does not have a #NamedQuery of course.
#Entity
#Table(schema="prd", name="PRDITEM", uniqueConstraints= {#UniqueConstraint(columnNames= {"prditmNO"})})
#Cache(expiry=com.quoka.qis.lib.persistence.Constants.SHORT_CACHE_PERIODE_MS)
#NamedQuery(name = "PrdItem.findByNo", query = "select pi from PrdItem pi where pi.no = ?1",
hints={
#QueryHint(name=QueryHints.BATCH, value="pi.jrnls"),
#QueryHint(name=QueryHints.BATCH, value="pi.bookings")//,
}
)
public class PrdItem {....
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="prditmID", insertable = false, nullable=false, unique=true)
private Long id;
EclipseLink has a BatchFetch annotation you can add to the mapping:
http://eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_batchfetch.htm
JPA 2.0 also has a find signature that takes in the class, key and properties map.

Hibernate OneToMany mapping

I have two model classes: Equity and EquityData. There is a OneToMany relationship from Equity to EquityData. I'm having a hard time getting Hibernate to bind the way I want it to.
#Entity
#Table(name="equities")
public class Equity
{
#Id
#GeneratedValue
#Column(name="Equity_ID")
private Integer id;
private String symbol;
#OneToMany(mappedBy="equity")
private List<EquityData> equityData;
...
}
#Entity
public class EquityData
{
#Id
#GeneratedValue
#Column(name="id")
private Integer id;
#ManyToOne
#JoinColumn(name="Equity_ID")
private Equity equity;
#Column(name="quote_time") private Date quoteTime;
#Column(name="quote_type_id") private Integer quoteTypeId;
#Column(name="value") private BigDecimal value;
...
}
Now an Equity can have many EquityQuotes, but there will always be a "most recent" quote (the one with the latest quoteTime). Right now, the way I have Hibernate bind to my entities, it'll retrieve the Equity and all the EquityData's. I only want it to retrieve the latest EquityData for each EquityDataType (i.e. i dont care about yesterday's data, just today's).
In SQL, it would look like this:
select d.equity_id, d.quote_type_id, d.value, max(quote_time)
from equities e, equity_data d
where e.equityID = d.equity_id and e.symbol = :symbol
group by d.equity_id, d.quote_type_id;
I'd appreciate any help! I don't think it matters, but I'm using this in the Stripes Web Framework.
You can set the fetch type as LAZY on your equity data list and then write a named query and fetch only today's equity data. Since you are using Hibernate, you can achieve this using the Criteria API as well.
You can set a criteria to fetch the latest quote from the database like,
Criteria crit = session.createCriteria(Equity.class);
//your criteria goes here....
crit.createCriteria(last_quoted);
List<?> entity = crit.list();
for(Iterator<?> it = equity.iterator();it.hasNext();){
Equity equity = (Equity) it.next();
//print the latest quotes based on the criteria you provided
}
session.close();
}
//catch(Exception e){ //display exeption;}
You can create another field to recover only the EquityData from today, adding an #Where clause to it:
#OneToMany(mappedBy = "equity")
#Where(clause = "quoteTime >= TODAY")
private List<EquityData> equityDataFromToday;
Then, you must use the field equityDataFromToday to access your data, instead of equityData (which will contain all of them)

How to create Many-One Mapping in hibernate?

I want to create Many-One Mapping between two tabels, Expense(ID, NAME, CATEGORY) and
Category(ID, NAME).
In my class i have created a field 'Category category' and its setters and getters.
I did them after seeing some stuff from internet. What are all the changes i have to do in my Category.java class. For now, its looks like,
public class Category{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int catId;
private String catName;
public Category() {
}
public int getCatId() {
return this.catId;
}
public void setCatId(int catId) {
this.catId = catId;
}
public String getCatName() {
return this.catName;
}
public void setCatName(String catName) {
this.catName = catName;
}
}
I dont want to do mappings with xml config. I think, annotations is good for a beginner like me.
And my Old! SQL query looks like,
SELECT EXPENSES.EXPNS_ID, EXPENSES.CAT_ID, EXPENSES.NAME, CATEGORY.CAT_NAME FROM EXPENSES INNER JOIN CATEGORY ON EXPENSES.CAT_ID = CATEGORY.CAT_ID WHERE USER_NAME="+currentUserName
How to use inner join in Hibernate?
Any Suggestions!!
Thanks!
Update
Thanks for all answerers,
I tried what you told and it returns a empty list.
To, test i set the 'userName=Tamil' which is in the table.
The query generated by Hibernate is looks like below,
select expens0_.expnsId as expnsId1_, expens0_.catId as catId1_, expens0_.category_catId as category7_1_, expens0_.userName as userName1_ from Expens expens0_ inner join Category category1_ on expens0_.category_catId=category1_.catId where expens0_.userName=?
As a beginner, i have some doubts in JPQL, I want catName from Category[catId, catName] table. And the catId is also available in Expens[expnsId, catId, userName].
By adding the below lines in Expens.java class, how it will give me catName along with the other variables in the Expens table.
#ManyToOne
private Category category
// getters, setters
I cant able to understand it. Without understanding this i cant move further, i have to give more mappings in my project. If clear with this mapping, i can move to the rest with confidence.
The query i used is pascal's version: Query query = hSession.createQuery("SELECT e FROM Expens e JOIN e.category c WHERE e.userName = :userName").setParameter("userName", userName);
For me, the query generated by hibernate is looks like same as my Old SQl query. I cant able to find problem here.
Actually, a big part of the documentation that would be useful in your case is located in the Hibernate Annotations Reference Guides (links provided below). Reading it would be very worth it.
That being said, regarding your specific question, the simplest possible mapping would be:
#Entity
public class Expense {
#Id #GeneratedValue
private Long;
#ManyToOne
private Category category
// getters, setters
...
}
That's all.
If you want to make it bi-directional, you'll have to add a OneToMany on the other side (and don't forget the mappedBy element since the association is bidirectional):
#Entity
public class Category {
#Id #GeneratedValue
private Long id;
#OneToMany(mappedBy="category")
private Set<Expense> expenses = new HashSet<Expense>();
....
}
And a possible JPQL query would be:
SELECT e FROM Expense e JOIN e.category c WHERE e.username = :username
Update: Hibernate and JDBC are different. With Hibernate, you need to think objects and the above HQL query (which was more an example) will actually return a List<Expense>. To get a category name, iterate over the results and navigate through the association. For example:
List<Expense> expenses = ... // some code to retrieve a list by username
for (Expense expense : expenses) {
System.out.println(expense.getCategory().getName());
}
References
2.2. Mapping with JPA (Java Persistence Annotations)
2.2.5.2. Many-to-one
As Bozho suggested,
#ManyToOne(fetch=FetchType.EAGER) // Gonna be eager by default anyway
#JoinColumn(name="CATEGORY_ID")
private Category category;
Plus this in your Category class to make it bidirectional,
#OneToMany(mappedBy="category")
private List<Expense> expense;
You need not do an inner join like that. When you query the expense, the related category will automatically get loaded eagerly, most likely using join.
In your Expense class have:
#ManyToOne
#JoinColumn(name="CATEGORY_ID")
private Category category
As pointed in the comments, if you need to access all expenses in a given category, i.e. have the one-to-many relationship, you can have:
#OneToMany
private List<Expense> expenses;
I, for example, prefer to use as little #OneToMany mappings as possible - you'd have to manager eager/lazy loading, at some point limiting the number of results, etc. For them I tend to use HQL queries that fetch the subset of objects (expenses in your case) that I need.

Categories