How Join hibernate Value objects using HQL query? - java

Hi i'm New to write HQL Query please help me.....
my Hibernate have three ValueObjects ie.
#Entity
#Table(name="user")
public class UserVO {
#Id
#Column(name="S_ID")
private String s_id;
#Column(name="FIRSTNAME")
private String firstName;
private String email;
}
CourseVO class
#Entity
#Table(name="course")
public class CourseVO
{
#Id
#Column(name="S_ID")
public String s_id;
#Column(name="NAME")
public String name;
}
Skillset VO
#Entity
#Table(name="skillset")
public class SkillsetVO
{
#Id
#Column(name="S_ID")
public String s_id;
#Column(name="COURSE_ID")//Foreign Key "USER"
public String course_id;
#Column(name="USER_ID")//Foreign key "COURSE"
public String user_id;
#Column(name="TEACH_EXP")
public String teach_Exp;
}
Now How to get Values of FirstName,NAME,TEACH_EXP values using EMAIL of USER table using HQL query

If you want to use join syntax in HQL you must work out your mapping accordingly as joins are enabled by mapping.
#Entity class A { #OneToMany private List<B> bs; }
#Entity class B { #Basic int n; }
Enables
select b from A a inner join a.b where a = :id
But with your mapping this is not possible. Also bear in mind that in terms of efficiency most of the RDBMs will perform an inner join on a where a.id = b.id.
select u.firstName, c.name, s.teach_Exp
from UserVO u, CourseVO c, SkillsetVO s
where
u.s_id = s.user_id
and c.s_id = s.course_id
and u.email = :email
But I think that you must review you association. Since looks to me that SkillsetVO.user_id should be SkillsetVO.User (an association to a UserVO entity and same for CourseVO).

Related

Spring Data Projection with OneToMany returns too many results

I have a JPA entity (Person) with onetomany relation (ContactInfo).
#Entity
public class Person {
#Id
#GeneratedValue
private Integer id;
private String name;
private String lastname;
private String sshKey;
#OneToMany(mappedBy = "personId")
private List<ContactInfo> contactInfoList;
}
#Entity
public class ContactInfo {
#Id
#GeneratedValue
private Integer id;
private Integer personId;
private String description;
}
I've defined a projection interface that includes this onetomany relation as described here.
public interface PersonProjection {
Integer getId();
String getName();
String getLastname();
List<ContactInfo> getContactInfoList();
}
public interface PersonRepository extends JpaRepository<Person,Integer> {
List<PersonProjection> findAllProjectedBy();
}
When I retrieve the data with findAllProjectedBy the result contains too many rows. It looks like the returned data is the result of a join query similar to:
select p.id, p.name, p.lastname, ci.id, ci.person_id, ci.description
from person p
join contact_info ci on ci.person_id = p.id
For example for this data set:
insert into person (id,name,lastname,ssh_key) values (1,'John','Wayne','SSH:KEY');
insert into contact_info (id, person_id, description) values (1,1,'+1 123 123 123'), (2,1,'john.wayne#west.com');
The findAllProjectedBy method returns 2 objects (incorrectly) and the standard findAll returns 1 object (correctly).
Full project is here
I've done some debugging and it seems that the problem is with the jpa query.
The findAll method uses this query:
select generatedAlias0 from Person as generatedAlias0
The findAllProjectedBy uses this query:
select contactInfoList, generatedAlias0.id, generatedAlias0.name, generatedAlias0.lastname from Person as generatedAlias0
left join generatedAlias0.contactInfoList as contactInfoList
Does anyone know how to fix this invalid behaviour?
A quick fix for this problem is described here:
https://jira.spring.io/browse/DATAJPA-1173
You need to describe one of the single projection attributes with a #Value annotation. For the example posted above you will end up with:
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
public interface PersonProjection {
#Value("#{target.id}")
Integer getId();
String getName();
String getLastname();
List<ContactInfo> getContactInfoList();
}

How to use hibernate query on two tables (join table)?

I have these tables: cont(id_cont, user, pass)
emp(emp_id, name, cont_id_cont (fk))
#Entity
#Table(name = "emp", catalog = "", uniqueConstraints = {
#UniqueConstraint(columnNames = "cont_id_cont") })
public class Emp implements java.io.Serializable{
private int id_emp;
private ContUser contUser;
private String name;
and
#Entity
#Table(name = "cont", catalog = "", uniqueConstraints = {
#UniqueConstraint(columnNames = "pass") })
public class Cont implements java.io.Serializable{
private int id_cont;
private String user;
private String pass;
private Set<Emp> empForCont = new HashSet<Emp>(0);
}
Now: I want this query:
select cont.user, emp.name, emp.cont_id_cont from cont
inner join emp on cont.id_cont= emp.cont_id_cont where cont.user = 'gbs04405';
This style of accessing data is not what ORM is intended for. If you are using Hibernate, you should (usually) access data through objects. To make this work, instead of embedding SQL like constraints, define relations #OneToMany, #ManyToOne, and/or #ManyToMany between objects where necessary.
In addition, you should consider using HQL (or JPQL) instead of pure SQL, to achieve what you want.
It should be something like this:
SELECT e FROM Emp e JOIN e.contUser u WHERE u.user = :userstring
You can check here for further JPQL syntax.

JPQL - How can I get an extra param inside my entity?

I am new to JPQL and I am trying to get an extra parameter that is not in the entity, but I am not finding how to do it.
Through searched here in the forum I found out that some uses a DTO for it, but I am not knowing how to apply that.
Here is my entity:
#Entity
#Table(name = "person")
public class Person implements Serializable {
private int id;
private String name;
private String email;
private int age;
...
}
And my JPQL:
SELECT COUNT(a.name) as countOfNames, a FROM Person a WHERE a.name like :name
How can I get the countOfNames result inside of myentity object since it is not a column?
The simplest way is to use a constructor expression
package com.entites
public class PersonDto {
private Person person;
private Integer countOfNames;
public PersonDto(Person person, Integer countOfNames) {
this.person = person;
this.countOfNames = countOfNames;
}
}
select new com.entites.PesronDto(a, count(a.name))
from Person a
where a.name like :name

JPA Join on specific field

I have this scenario:
User and his related UserRole entity classes, as below:
#Entity
#Table(name="USER")
public class User implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="ID", unique=true, nullable=false)
private int id;
#Column(name="USERNAME", unique=true, nullable=false, length=255)
private String username;
#OneToMany(mappedBy="user")
private List<UserRole> userRoles;
}
and
#Entity
#Table(name="user_roles")
public class UserRole implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="user_role_id", unique=true, nullable=false)
private int userRoleId;
#Column(nullable=false, length=45)
private String role;
#ManyToOne
#JoinColumn(name="username", nullable=false)
private User user;
}
Now, I need to query all users that have a specific role. I'm trying making join with JPA Specifications, like that:
Join<User, UserRole> join = root.join(User_.userRoles);
Expression<String> match = join.get(UserRole_.role);
Predicate predicate = builder.equal(match, "ROLE_USER");
The problem is that the generated join will be between User.id and UserRole.username and the query will obviously have no results.
select count(user0_.ID) as col_0_0_ from USER user0_ inner join
user_roles userroles1_ on user0_.ID=userroles1_.username where
userroles1_.role='ROLE_USER'
I need instead to have the on clause both on username fields:
... from USER user0_ inner join
user_roles userroles1_ on user0_.USERNAME=userroles1_.username ...
I noticed that there is the .on method of Join class who:
Modify the join to restrict the result according to the specified ON
condition. Replaces the previous ON condition, if any. Return the join
object
Is this the correct approach? If so, how could I implement that?
Join<User, UserRole> join = root.join(User_.userRoles).on(????);
Thank you in advance.
UPDATE:
UserRole_ metamodel class
#StaticMetamodel(UserRole.class)
public class UserRole_ {
public static volatile SingularAttribute<UserRole, Integer> userRoleId;
public static volatile SingularAttribute<UserRole, String> role;
public static volatile SingularAttribute<UserRole, User> user;
}
User_ metamodel class:
#StaticMetamodel(User.class)
public class User_ {
public static volatile SingularAttribute<User, Integer> id;
public static volatile SingularAttribute<User, String> username;
public static volatile ListAttribute<User, UserRole> userRoles;
}
You need to use referencedColumnName:
#ManyToOne
#JoinColumn(name="username", referencedColumnName="username", nullable=false)
private User user;
With only #JoinColumn(name="username") you tell Hibernate that the join column in user_roles is named username - but it still expects that it contains the values of the #Id property of User. If you create the DDL for your schema you will see that Hibernate generates a number column for user_roles.username.
Once again, you should check what the user_roles.username column contains, because by default, it contains the #Id column of the referenced entity, here the referenced entity is User, and its #Id column is id (in your schema: ID) and not username (in your schema: USERNAME).
Although, here's an example of how to write what you described here:
The problem is that the generated join will be between User.id and
UserRole.username and the query will obviously have no results. I need
instead to have the on clause both on username fields:
In JPQL (using JPA 2.1)
// get entity manager as 'em'
TypedQuery<User> q = em.createQuery("SELECT u FROM User u INNER JOIN UserRole ur ON ur.user = u.username WHERE ur.role = 'ROLE_USER'", User.class);
List<User> results = q.getResultList();

Hibernate generating a query from Named Query that joins on the wrong column?

I am using named query (hibernate 4).Entity defined as below.
#Entity
#NamedQuery(
name = "findAllProduct",
query = "SELECT PC.pincode,PO.description"
+" FROM PRODUCT_VENDOR_PAYMENT_OPTION_LOCATION PVPOL"
+" INNER JOIN PVPOL.paymentId PID"
+" INNER JOIN PVPOL.pincode PC"
+" INNER JOIN PVPOL.paymentOptions PO"
+" where PVPOL.id = :id"
)
public class PRODUCT_VENDOR_PAYMENT_OPTION_LOCATION extends baseEntity.Entity {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#Column(name="Payment_Id")
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER,mappedBy="id")
private Set<Product_Catalog_Vendor> paymentId;
#Column(name="pincode_id")
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER,mappedBy="pincode_id")
private Set<Pincodes> pincode;
#Column(name = "payment_options")
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER,mappedBy="paymentOptions")
private Set<Payment_Options> paymentOptions;
//Protected setter getter here
}
Hibernate generating below sql:-
select pincode2_.pincode as col_0_0_, paymentopt3_.Description as col_1_0_
from PRODUCT_VENDOR_PAYMENT_OPTION_LOCATION product_ve0_
inner join Product_Catalog_Vendor paymentid1_
on product_ve0_.id=paymentid1_.Id
inner join Pincodes pincode2_
on product_ve0_.id=pincode2_.pincode_id
inner join payement_options paymentopt3_
on product_ve0_.id=paymentopt3_.payment_options
where product_ve0_.id=?
Instead of
select pincode2_.pincode as col_0_0_, paymentopt3_.Description as col_1_0_
from PRODUCT_VENDOR_PAYMENT_OPTION_LOCATION product_ve0_
INNER JOIN product_catalog_vendor paymentid1_
ON **product_ve0_.payment_id = paymentid1_.id**
INNER JOIN PINCODES pincode2_
ON **product_ve0_.pincode_id = pincode2_.pincode_id**
INNER JOIN payement_options paymentopt3_
ON **product_ve0_.payment_options=paymentopt3_.payment_options**
where product_ve0_.id=1;
Product_catalog_vendor class:
#Entity
public class Product_Catalog_Vendor extends baseEntity.Entity {
#Id
#Column(name="Id")
private int id ;
//Setters and getters here
}
Pincodes Entity:
#Entity
public class Pincodes extends baseEntity.Entity {
#Id
private int pincode_id;
#Column(name="pincode")
private int pincode;
//Setters and getters here
}
payment_options Entity below:
#Entity
#Table(name="payement_options")
public class Payment_Options extends baseEntity.Entity {
#Id
#Column(name="payment_options")
private int paymentOptions;
//Setter getter
}
I have searched on many sites but unable to find the cause behind the scene. Please give me suggestions if i am doing something wrong. some good references would be appreciated. Thanks
just to get your problem correcty, your query joins on paymentid1_.Id instead of paymentid1_.id? or am I missing the differenz between the expected and the real query?
I'm not a pro but just guessing I would say your query is joining to the id of the Product_Catalog_Vendor:
#Id
#Column(name="Id")
private int id ;
so because thats why its Id and not id...
I think you don't need mappedBy at all due to unidirectional mapping or,anyway ,you are using them in a weird way.
mappedBy is necessary only if association is bidirectional (not your case) and should refers to a field which type is of the same type of entity where mappedBy is declared (and not a String type like in your case).You used mappedBy in a way like referencedColumnName property
In your example:
#Entity
public class Product_Catalog_Vendor extends baseEntity.Entity {
#ManyToOne
private PRODUCT_VENDOR_PAYMENT_OPTION_LOCATION pvpol;
}
and
public class PRODUCT_VENDOR_PAYMENT_OPTION_LOCATION extends baseEntity.Entity {
#Column(name="Payment_Id")
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER,mappedBy="pvpol")
private Set<Product_Catalog_Vendor> paymentId;
}

Categories