This is my HQL query, but it isn't working and is throwing an error.
Hql query:
SELECT
*
FROM
TABLEA A
LEFT JOIN
A.TABLEB B
WHERE
A.COLUMNNAME = B.COLUMNAME
and it causes this error:
org.hibernate.QueryException:
This Query caught Exception. could not resolve property: of TABLEB:TABLEA.
How can I solve this problem? Actually I retrieved a value from more than one table. This query doesn't work with CreateQuery(strQuery).
In HQL you can use LEFT JOIN only with linked property in main entity:
Sample
EntityA has an object entityB of type EntityB so you can
SELECT A FROM EntityA A LEFT JOIN A.entityB B WHERE ...
IF EntityA haven't entityB property but is EntityB have a property entityA, you can't write this:
SELECT A FROM EntityA LEFT JOIN EntityB B WHERE B.entityA = A
because you have an error. This is an Hibernate issue not resolved yet.
Related
I have 2 different entities. table1 has a column which is primary key of table2.
both of the tables has respected repository.
If I write below query in one of the repository it gives error
QuerySyntaxException: unexpected token:
#Query("select new stats.UserCountDTO(b.objectiveId, count(b.objectiveId), a.locationCountry)"+
" from UserIdentityEntity a, UserObjectiveEntity b where b.userIdentityId == a.id and b.cId = ?1")
How can I write join queries in this case using spring data jpa?
You just make a mistake. The
b.userIdentityId == a.id
should be:
b.userIdentityId = a.id
I have come across a weird behaviour when using QueryDSL integrated with Spring Data JPA:
I have a ManyToOne relation between Project and Person. If I get all the projects belonging to a user by owner id (foreign key) everything works as expected:
QProject project = QProject.project;
QPerson owner = project.owner;
List<Project> projects = from(project).leftJoin(owner).fetch()
.where(owner.id.eq(id)).list(project);
Generated query:
select
project0_.id as id1_1_0_,
person1_.id as id1_0_1_,
project0_.creation_date as creation2_1_0_,
project0_.name as name3_1_0_,
project0_.owner as owner4_1_0_,
person1_.name as name2_0_1_
from
project project0_
left outer join
person person1_
on project0_.owner=person1_.id
where
project0_.owner=?
However, let's say we want to get all the projects belonging to a person by a field that isn't the foreign key (for instance the owner's name):
QProject project = QProject.project;
QPerson owner = project.owner;
List<Project> projects = from(project).leftJoin(owner).fetch()
.where(owner.name.eq(name)).list(project);
In these cases, the table Person is joined twice unnecessarily (notice person1_ and person2_):
select
project0_.id as id1_1_0_,
person1_.id as id1_0_1_,
project0_.creation_date as creation2_1_0_,
project0_.name as name3_1_0_,
project0_.owner as owner4_1_0_,
person1_.name as name2_0_1_
from
project project0_
left outer join
person person1_
on project0_.owner=person1_.id cross
join
person person2_
where
project0_.owner=person2_.id
and person2_.name=?
Any idea why this is happening and how to avoid it?
You need to create an alias to ensure that the first join is reused in the where part
QProject project = QProject.project;
QPerson owner = new QPerson("owner");
List<Project> projects = from(project)
.leftJoin(project.owner, owner).fetch()
.where(owner.name.eq(name))
.list(project);
There two tables in my Oracle database product and product_image. They have one-to-many relationship from product to product_image. Therefore, the relationship can be mapped in Hibernate something like the following.
The product entity:
#Entity
#Table(name = "PRODUCT", catalog = "", schema = "WAGAFASHIONDB")
public class Product implements java.io.Serializable
{
#OneToMany(mappedBy = "prodId", fetch = FetchType.LAZY)
private Set<ProductImage> productImageSet;
}
#Entity
#Table(name = "PRODUCT_IMAGE", catalog = "", schema = "WAGAFASHIONDB")
public class ProductImage implements java.io.Serializable
{
#ManyToOne(fetch = FetchType.LAZY)
private Product prodId;
}
I need to query that can fetch a list of rows with the maximum prod_image_id (primary key of the prduct_image table) from each group of products in the product_image table.
This was my previous question. This can be done with the following SQL.
SELECT
pi.prod_image_id,
pi.prod_id, pi.prod_image
FROM
product_image pi
INNER JOIN (
SELECT
MAX(pi.prod_image_id) AS prod_image_id
FROM
product_image pi
GROUP BY
pi.prod_id
) prod_image
ON pi.prod_image_id=prod_image.prod_image_id
The answer to that question corresponds to the following correct HQL.
SELECT
pi.prodImageId,
pi.prodId
FROM
ProductImage pi
WHERE
pi.prodImageId in (
SELECT
MAX(pis.prodImageId)
FROM
Product p
INNER JOIN
p.productImageSet pis
GROUP BY
p.prodId
)
This brings the following result exactly as intended.
PROD_IMAGE_ID PROD_ID PROD_IMAGE
662 284 3562298873030291049_Winter.jpg
644 283 7551758088174802741_9392401244_SS_2505.jpg
595 124 298082252715152799_SS_5012.jpg
566 62 7826143854352037374_SS_5004-A.jpg
But what I actually need is that the result set retrieved by the above SQL/HQL needs to be combined with the product table with LEFT OUTER JOIN so that it can retrieve each product from the product table regardless of their images in the product_image table something like the following.
PROD_IMAGE_ID PROD_ID PROD_IMAGE
662 284 3562298873030291049_Winter.jpg
644 283 7551758088174802741_9392401244_SS_2505.jpg
595 124 298082252715152799_SS_5012.jpg
- 101 -
- 81 -
566 62 7826143854352037374_SS_5004-A.jpg
This could be done by the following native SQL but doesn't seem possible with HQL which allows a subquery only in the SELECT and the WHERE clauses, a subquery in the FROM clause is disallowed in HQL.
SELECT
t.prod_image_id,
p.prod_id,
t.prod_image
FROM
product p
LEFT OUTER JOIN(
SELECT
pi.prod_image_id,
pi.prod_id,
pi.prod_image
FROM
product_image pi
INNER JOIN (
SELECT
MAX(pi.prod_image_id) AS prod_image_id
FROM
product_image pi
GROUP BY
pi.prod_id
) prod_image
ON pi.prod_image_id=prod_image.prod_image_id
)t ON p.prod_id=t.prod_id ORDER BY p.prod_id DESC;
My Google search says this is not feasible with a single HQL statement. Is this possible somehow with HQL? Please confirm me.
You're right, you can't use subqueries in from clause.
http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html_single/#queryhql-subqueries
But you can use a separate query like:
select p
from Product p
where p.productImageSet is empty
to find the products that has no product image.
I would create an Oracle view that implements your query that gives you what you want with a simple select in HQL.
I'm currently having the same table relationship in MySQL. I'm currently trying to learn JPA. Accordingly, I'm using JPA 2.0 provided by Hibernate - version 4.2.7 final. The following JPQL,
select
p.prodId,
pi.productImageId,
p.prodName,
pi.prodImage
from
Product p
left join
p.productImageSet pi
where
pi.productImageId in (
select
max(productImageId) as productImageId
from
ProductImage
group by
prodId
)
or pi.productImageId is null
order by p.prodId
and the corresponding criteria query,
CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple>criteriaQuery=criteriaBuilder.createTupleQuery();
Metamodel metamodel=entityManager.getMetamodel();
EntityType<Product>entityType=metamodel.entity(Product.class);
Root<Product>root=criteriaQuery.from(entityType);
SetJoin<Product, ProductImage> join = root.join(Product_.productImageSet, JoinType.LEFT);
List<Selection<?>>selections=new ArrayList<Selection<?>>();
selections.add(root.get(Product_.prodId));
selections.add(root.get(Product_.prodName));
selections.add(join.get(ProductImage_.prodImage));
selections.add(join.get(ProductImage_.productImageId));
criteriaQuery.multiselect(selections);
Subquery<Long>subquery=criteriaQuery.subquery(Long.class);
Root<ProductImage> subRoot = subquery.from(ProductImage.class);
subquery.select(criteriaBuilder.max(subRoot.get(ProductImage_.productImageId)));
subquery.groupBy(subRoot.get(ProductImage_.prodId).get(Product_.prodId));
Predicate []predicates=new Predicate[2];
predicates[0]=criteriaBuilder.in(join.get(ProductImage_.productImageId)).value(subquery);
predicates[1]=join.get(ProductImage_.productImageId).isNull();
criteriaQuery.where(criteriaBuilder.or(predicates));
criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Product_.prodId)));
TypedQuery<Tuple> typedQuery = entityManager.createQuery(criteriaQuery);
List<Tuple> tuples = typedQuery.getResultList();
Both of them, JPQL and criteria query produce the following SQL query.
select
product0_.prod_id as col_0_0_,
productima1_.product_image_id as col_1_0_,
product0_.prod_name as col_2_0_,
productima1_.prod_image as col_3_0_
from
social_networking.product product0_
left outer join
social_networking.product_image productima1_
on product0_.prod_id=productima1_.prod_id
where
productima1_.product_image_id in (
select
max(productima2_.product_image_id)
from
social_networking.product_image productima2_
group by
productima2_.prod_id
)
or productima1_.product_image_id is null
order by
product0_.prod_id desc
resulting in fetching the desired result set as mentioned in the question - not in the way we can see in the usual RDBMS systems but it works.
This can be done, if the query statement is slightly modified. Accordingly the following criteria query does what exactly is needed.
CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaQuery<ProductUtils>criteriaQuery=criteriaBuilder.createQuery(ProductUtils.class);
Metamodel metamodel = entityManager.getMetamodel();
Root<Product> root = criteriaQuery.from(metamodel.entity(Product.class));
ListJoin<Product, ProductImage> join = root.join(Product_.productImageList, JoinType.LEFT);
List<Selection<?>>selections=new ArrayList<Selection<?>>();
selections.add(root.get(Product_.prodId));
selections.add(root.get(Product_.prodName));
selections.add(join.get(ProductImage_.prodImage));
selections.add(join.get(ProductImage_.productImageId));
criteriaQuery.select(criteriaBuilder.construct(ProductUtils.class, selections.toArray(new Selection[0])));
Subquery<Long> subquery = criteriaQuery.subquery(Long.class);
Root<ProductImage> prodImageRoot = subquery.from(metamodel.entity(ProductImage.class));
subquery.select(prodImageRoot.get(ProductImage_.productImageId));
subquery.where(criteriaBuilder.equal(root, prodImageRoot.get(ProductImage_.prodId)), criteriaBuilder.lessThan(join.get(ProductImage_.productImageId), prodImageRoot.get(ProductImage_.productImageId)));
criteriaQuery.where(criteriaBuilder.exists(subquery).not());
criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Product_.prodId)));
List<ProductUtils> list = entityManager.createQuery(criteriaQuery).getResultList();
This criteria query produces the following desired SQL query that does equally the same function which is needed as specified in the question.
select
product0_.prod_id as col_0_0_,
product0_.prod_name as col_1_0_,
productima1_.prod_image as col_2_0_ ,
productima1_.product_image_id as col_3_0_
from
social_networking.product product0_
left outer join
social_networking.product_image productima1_
on product0_.prod_id=productima1_.prod_id
where
not (exists (select
productima2_.product_image_id
from
social_networking.product_image productima2_
where
product0_.prod_id=productima2_.prod_id
and productima1_.product_image_id<productima2_.product_image_id))
order by
product0_.prod_id desc
I have a standard many-to-many relationship set up. Entity A can have many of Entity B, and vice versa.
I'm trying to get a list of all Entity A that do NOT have any corresponding Entity B. In SQL, I'd run a query like this:
SELECT a.* FROM entity_a a LEFT JOIN a_b r ON r.AID = a.id WHERE r.BID IS NULL
In this query, a_b is the linking table.
I'm trying to write a DQL statement (or use some other method) to get the same result, but the following does not work:
SELECT s FROM VendorMyBundle:EntityA s LEFT JOIN VendorMyOtherBundle:EntityB u WHERE u IS NULL
How can I achieve what I'm trying to do?
First, I have to underline that usually you should JOIN on the property of the entity (i.e. s), e.g. instead of:
SELECT s FROM VendorMyBundle:EntityA s
LEFT JOIN VendorMyOtherBundle:EntityB u WHERE u IS NULL
you should have something like:
SELECT s FROM VendorMyBundle:EntityA s
LEFT JOIN s.mylistofb u WHERE u IS NULL
where I'm supposing that in entity A you have defined your relationship as:
class A{
// ...
/**
* #ManyToMany(targetEntity="Vendor\MyBundle\Entity\EntityB")
* #JoinTable(name="as_bs",
* joinColumns={#JoinColumn(name="a_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="b_id", referencedColumnName="id", unique=true)}
* )
**/
private $mylistofb;
This stated, if the query is not working yet, then try the following:
SELECT s FROM VendorMyBundle:EntityA s
WHERE SIZE(s.mylistofb) < 1
It is simplest than the previous and also comes from the official docs (i.e. see "phonenumbers example").
I have three entities A,B,C.
EntityA:
Properties:
Id,Name
Relationships:
ABRelation(A-->>B)
EntityB:
Properties:
Id,Name
Relationships:
BARelation(B-->A)
BCRelation(B-->>C)
EntityC:
RoleId
CBRelation(C-->>B)
Now I need to fetch records from Entity A having some RoleId = 23 which is contain in C.
Could you please help me quickly.Thanks in Advance.
SELECT a.Id, a.Name,
FROM EntityA a INNER JOIN EntityB b
ON a.Id= b.EntityA_Id(foriegn key) JOIN EntityC as c
ON b.EntityC_Id(foriegn key) = c.Id
WHERE c.RoleId=23