I'm trying to perform a composite key query using #embeddable.
Here's what I have thus far.
#Embeddable
public class IfasvVendorPK implements Serializable{
#Column(length = 4, nullable = false)
protected String peId;
#Column(length = 8, nullable = false)
protected String peAddrCd;
Entity
#Entity
public class IfasvVendor implements Serializable {
#EmbeddedId
private IfasvVendorPK ifasvVendorPK;
Query
List contains two pks. Not sure if I should be using a list for this.
Query query = session.createQuery("from IfasvVendor t0 where t0.ifasvVendorPK.peId=:id");
query.setParameter("id", list);
query.list();
I also wasn't sure how to get the object once I get the query working.
I believe that the following should work:
Query query = session.createQuery("from IfasvVendor t0 where t0.ifasvVendorPK.peId in (:id)");
query.setParameterList("id", list);
query.list();
You must enclose the named parameter in parenthesis in your query and use setParameterList. See the javadoc for setParameterList here.
The query results will be in the list returned by: query.list(). This returns an unchecked list which you may want to cast to List<IfasvVendor>.
btw. this is not a composite key query. see #Perception comment...
Related
Currently I have a repository where I'm using a native query to find out the first 10 unique ids and these ids should be fetched with the recent ones first. To do this I'm using the following query in my repository class:
#Repository
public interface HomePageRepository extends JpaRepository<TransferEntity, Integer> {
#Query(value="select DISTINCT transfer_to from transfers_table where transfer_from= :transfer_from ORDER BY transaction_date DESC LIMIT 10;", nativeQuery=true)
public ArrayList<Integer> getTransferRequests(Integer transfer_from);
}
The following is my entity class I'm using:
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "transfers_table")
public class TransferEntity {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer Id;
private Integer transfer_from;
private Integer transfer_to;
private Double transaction_amount;
#Column(nullable = false, updatable = false)
#CreationTimestamp
private Date transaction_date;
}
Now this is giving me the following error when I try to run it:
java.sql.SQLException: Expression #1 of ORDER BY clause is not in SELECT list, references column 'db.transfers_table.transaction_date' which is not in SELECT list; this is incompatible with DISTINCT
This same query works when I remove the Order by clause from the statement, but then I cannot fetch the recent ids first.
use subquqries:
select DISTINCT transfer_to from (
select transfer_to, transaction_date from transfers_table where transfer_from= 6 ORDER BY transaction_date DESC LIMIT 10
) as x
Demo
I am trying to query for a Java Object using HQL which is performing filters based on the Object's Java Map that it has.
Essentially what I want to ask is 'give me all the error reports where mapkey1=val_x and mapkey2=val_y'
I have this object (stripped down)
#Entity
#Table(name = "error_report")
public class ErrorReport implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id", length=50)
private String id= UUID.randomUUID().toString();
#ElementCollection
#CollectionTable(name = "error_property", joinColumns = {#JoinColumn(name = "error_id", referencedColumnName = "id")})
#MapKeyColumn(name = "prop", length=50)
#Column(name = "prop_val")
#Type(type="text")
private Map<String, String> reportedProperties = new HashMap<>();
}
So I want ErrorReports based on the reportedProperties. I have set up a unit test and everything works perfectly when the reportedProperties Map has only 1 entry per ErrorReport. This is the HQL I used:
from ErrorReport as model where KEY(model.reportedProperties) = :A1 and VALUE(model.reportedProperties) = :A2
When the ErrorReport has 2 entries in the reportedProperties Map the query fails with the following error:
could not extract ResultSet
caused by
HsqlException: cardinality violation
When I look at the generated SQL and try and run it manually I can see it will not work, because the innter select is returning multiple results.
SELECT error_report_.id AS id1_2_, error_report_.product_url AS product_2_2_, error_report_.audit_id AS audit_id3_2_, error_report_.category_id AS
category4_2_, error_report_.error_desc AS error_de5_2_, error_report_.notifier_id AS notifier6_2_, error_report_.product_name AS
product_7_2_, error_report_.product_version AS product_8_2_, error_report_.error_time AS error_ti9_2_
FROM error_report error_report_
CROSS JOIN error_property reportedpr1_
CROSS JOIN error_property reportedpr2_
WHERE error_report_.id=reportedpr1_.error_id
AND error_report_.id=reportedpr2_.error_id
AND reportedpr1_.prop=?
AND
(SELECT reportedpr2_.prop_val FROM error_property reportedpr2_ WHERE error_report_.id=reportedpr2_.error_id)=?
Clearly there is something wrong with my HQL, but it seems to follow other examples I have found. Does anyone know what the syntax is?
I am using hibernate 5.4.9.Final
For anyone in the future, I had similar problem and solved it by applying join on the collection table combined with INDEX().
SELECT DISTINCT(model.id), model.product_url, ...
FROM ErrorReport as model
...
JOIN model.reportedProperties rProp
WHERE INDEX(rProp) = :A1 AND rProp = :A2
Here the INDEX(rProp) is the key and rProp is the value. Also DISTINCT was needed because it was returning duplicate records for me due to the map.
I'm using #query annotation but when I try to fetch count of records it throws
java.sql.SQLException: Column 'allowPartialPay' not found.
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1094) ~[mysql-connector-java-5.1.31.jar:na]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:997) ~[mysql-connector-java-5.1.31.jar:na]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:983) ~[mysql-connector-java-5.1.31.jar:na]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:928) ~[mysql-connector-java-5.1.31.jar:na]
at com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1162) ~[mysql-connector-java-5.1.31.jar:na]
at com.mysql.jdbc.ResultSetImpl.getBoolean(ResultSetImpl.java:1781) ~[mysql-connector-java-5.1.31.jar:na]
I'm writing my custom queries in repository.
InvoiceRepository.java
public interface InvoiceRepository extends JpaRepository<Invoice, Integer>{
Invoice findByInvoiceNumber(String invoiceNumber);
List<Invoice> findByUserId(int id);
#Query(value = "select c.id,c.business_name,count(i.id) from client c join invoice i on c.id = i.client_id where i.date <= :agingDate group by c.id",nativeQuery=true)
List<Invoice> findInvoiceCount(#Param("agingDate")Date agingDate);
}
ReportService.java
if(report.getReportBy().equals("invoiceCount")){
result = invoiceRepository.findInvoiceCount(report.getAgingDate());
}
Invoice.java
#Entity
#Table
public class Invoice {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
private int id;
#ManyToOne
private Client client;
#Column
private boolean allowPartialPay;
}
Database
It comes during mapping result set into java Invoice class (as you declared it as return type List for method findInvoiceCount() ). native query return in your case Object[] instead of List.
You can see it in log exception
ResultSetImpl.findColumn(ResultSetImpl.java:1162
So it happens in result mapping stage ,after query has executed.
#Query(value = "select c.id,c.business_name,count(i.id) from client
c join invoice i on c.id = i.client_id
where i.date <= :agingDate group by c.id",nativeQuery=true)
List<Invoice> findInvoiceCount(#Param("agingDate")Date agingDate);
spring data gets result set from query result and tries to map it into Invoice field by field (try to contruct Invoice class ). But actual type it's Object[].
If you need get some DTO as result your query , with fields like is result set : 'c.id,c.business_name,count(i.id)' use #SqlResultSetMapping (you can map result columns from select query into your dto). Or change return type from List to Object[] and iterate it as you need.
Here is example for Result Set Mapping: The Basics.
JSF application with hibernate
Is there a way to use a join to filter the results returned by criteria list?
Example: i have 2 tables. orders and customers.
#Entity(name = "order")
public class Order
{
#Id
private int id;
private String billingCustomerId;
private String shippingCustomerId;
private Date orderDate;
....
}
#Entity(name = "customer")
public class Customer
{
#Id
private String id;
private String name;
private String emailAddress
....
}
I need to return all orders for customers that are missing an email address and all orders that the order.billingCustomerId = null and order.shippingCustomerId = null.
The customer could match on the billingCustomerId or shippingCustomerId.
The SQL I would use
select o.* from order as o
LEFT join customer as c1 on o.billingCustomerId = c1.id
LEFT join customer as c2 on o.shippingCustomerId= c2.id
where (o.billingCustomerId is null and o.shippingCustomerId is null) or
(o.billingCustomerId is not null and c1.emailAddress is null) or
(o.shippingCustomerIdis not null and c2.emailAddress is null)
Hibernate Criteria
Criteria criteria1 = session.createCriteria(Order.class);
criteria.add(Restrictions.and(Restrictions.isNull("billingCustomerId"),
Restrictions.isNull("shippingCustomerId"));
List<Order> = criteria.list();
This will return the list of orders that billing /shipping customer = null.
How can i change the criteria to also include the orders for customers with missing email addresses?
Disjunction disjunciton = Restrictions.disjunction();
Criteria criteria = session.createCriteria(Order.class);
disjunciton.add(Restrictions.and(Restrictions.isNull("billingCustomerId"),
Restrictions.isNull("shippingCustomerId")));
disjunciton.add(...
...)
criteria.add(disjunciton);
List<Order> = criteria.list();
I have not been able to find examples of joining on a column, but only where the table have a common key.
I asked this question: Hibernate trouble getting composite key to work and discovered Hibernate can only create a join on columns that were created by relating 2 objects. I am going to add more to my answer to give more useful information but the best alternative you your case is to do a Session.createSQLQuery() using the query you showed above. Then before running the query put Query.addEntity(Order.class).addEntity(Customer.class). As long as your query returns the correct rows to fill out the Java objects correctly, Hibernate can populate them automatically. If that doesn't work you can still retrieve the data and populate it manually yourself.
I have a native sql query as the following :
for (init i=0; i<=2 ; i++) {
String sql = "Select * from accounts where id = ?";
Query query = em.createNativeQuery(sql,AccountBean.class);
query.setParameter(1, i );
AccountBean accountBean = (AccountBean)query.getSingleResult();
}
For the first loop it works correctly but any loop after the first one returns the same result as the first one , i debug it, the parameter changed , it works correctly if i change
Query query = em.createNativeQuery(sql,AccountBean.class);
to
Query query = em.createNativeQuery(queryString);
Regards
Wish79
Every JPA entity must have a primary key. Your JPA entities may not properly reflect the primary key, if any, on the database table.
I ran into the same problem. In my model class I had only one class variable annotated with #Id. However, that was not an accurate reflection of the table itself, which has a composite primary key. Thus, my query results returned the correct number of rows, but each confoundingly contained the same values, even though the actual data was different in the db. For example, this query:
Query query = entityManager.createQuery
("SELECT tbl FROM Tbl tbl WHERE tbl.id = 100
and tbl.code in ('A','B','C')");
...returned 10 rows, each showing a code of 'A'. But in actuality 9 of those 10 rows had a different code value ('B' or 'C'). It seemed as if the results were being cached and/or the tbl.code predicate was ignored. (That happened whether I used JPQL or Native SQL.) Very confusing.
To fix this I added an additional #Id annotation to my model to reflect the composite primary key:
#Id
#Column(name = "Code")
public String getCode() {
return this.code;
}
Now the query returns the data correctly and the code select criteria is no longer effectively ignored.
Edit: Although the above worked for me, on further research it seems a better approach to configure a separate JPA Entity composite primary key class. See http://docs.oracle.com/cd/E16439_01/doc.1013/e13981/cmp30cfg001.htm.
For example, here's an Entity class with an embedded primary key (see #EmbeddedId):
/**
* The persistent class for the SOME_TABLE database table.
*/
#Entity
#Table(name = "SOME_TABLE")
public class SomeTable implements Serializable {
#EmbeddedId
private SomeTablePk id;
#Column(name = "NUMBER_HRS")
private BigDecimal numberHrs;
...
...and here's the composite primary key class (see #Embeddable):
#Embeddable
public class SomeTablePk implements Serializable {
#Column(name = "SOME_ID")
private String someId;
#Column(name = "ANOTHER_ID")
private BigDecimal anotherId;
public String getSomeId() {
return someId;
}
...