Hibernate Criteria on Referenced table - java

I have a function that merges two tables, each of these tables has a column that I want to filter.
#Entity
public class Contacts {
#Id
private int id;
#ManyToOne //reference user_id = id
private User user;
#ManyToOne //reference people_id = id
private People people;
//getters and setters
}
#Entity
public class User {
private int id;
private int name;
private Enterprise enterprise;
//getters and setters
}
#Entity
public class People {
private int id;
private int name;
//..others fields
private Enterprise enterprise;
//getters and setters
}
I need to list all "Contacts" where my enterprise id = 1. On a simple select (SQLServer), it will be:
SELECT c.* FROM CONTACTS c
INNER JOIN User u ON u.id = c.user_id
INNER JOIN People p on p.id = p.people_id
WHERE u.empresa_id = 1
I can't figure out how to do it with Criteria API, I already tried the follow code, but I keep receiving an error.
//code..public List<Obj> list(int id) {
Criteria crit = session.createCriteria(Contacts.class);
crit.add(Restrictions.eq(user.enterprise.id, id)); //it doesn't work!
crit.list();
}
org.hibernate.QueryException: could not resolve property: user.enterprise.id of: sys.com.model.Contacts

here i am writing code for sample using criteria.
public List<Student_document> getUserById(int id) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(
Student_document.class);
criteria.add(Restrictions.eq("user_document.user_Id", id));
return criteria.list();
}

Related

returning a list of instances by the foreign key

I have two models, Owner and Contract. A contract has an instance of an owner, owner does not have a list of contracts. I'm trying to query my list of contracts, to return a list filtered by owner, ie, a list of contracts by owner.
I had tried to follow previous examples and use Criteria to write a custom query, but, following suggestions I've checked the docks and tried to use named queries instead, however, I'm still really struggling.
There was an unexpected error (type=Internal Server Error, status=500).
Named parameter not bound : ownerId; nested exception is org.hibernate.QueryException: Named parameter not bound : ownerId
My models look like this:
#Entity
#Table(name="Contracts")
#NamedQueries({
#NamedQuery(
name = "Contract.allContractsByOwner",
query = "SELECT c FROM Contract c WHERE c.owner.id LIKE :ownerId"
)
})
public class Contract {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private Long id;
#ManyToOne
private Owner owner;
#Column
private double price;
#Column
private String deliverDate;
public Contract(Owner owner, double price, String deliverDate) {
this.id = id;
this.owner = owner;
this.price = price;
this.deliverDate = deliverDate;
}
and
#Entity
#Table(name="Owners")
public class Owner {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private Long id;
#Column
private String name;
public Owner(String name){
this.name = name;
}
my contractRepoImpl
#Service
public class ContractRepositoryImpl implements ContractRepositoryCustom {
ContractRepository contractRepository;
#Autowired
EntityManager entityManager;
public List allContractsByOwner(Long ownerId) {
List contracts = entityManager.createQuery(
"SELECT c FROM Contract c WHERE c.owner.id LIKE :ownerId", Contract.class)
.getResultList();
return contracts;
}
}
which I name in my ContractRepo and ContractRepoCustom files, and then in my controller I map to it like so. But, when I query it in my browser I get the error in my terminal.
#GetMapping(value="/owners/{ownerId}/contracts")
public List allContractsByOwner(#PathVariable("ownerId") Long ownerId){
return contractRepository.allContractsByOwner(ownerId);
}
I appreciate this is probably beginners mistakes, I am trying to follow docs but get a bit stuck with syntax & where annotations need to go.
Thanks JB Nizet, got there in the end
I added parameters to my contractRepoImpl
#Service
public class ContractRepositoryImpl implements ContractRepositoryCustom {
ContractRepository contractRepository;
#Autowired
EntityManager entityManager;
public List allContractsByOwner(Long id) {
List contracts = entityManager.createQuery(
"SELECT c FROM Contract c WHERE c.owner.id = :ownerId", Contract.class)
.setParameter("ownerId", id)
.getResultList();
return contracts;
}
}
that then produced a SQL error, which I fixed by changing my #NamedQuery from 'LIKE' to '=' in my Contract class...
#NamedQueries({
#NamedQuery(
name = "Contract.allContractsByOwner",
query = "SELECT c FROM Contract c WHERE c.owner.id = :ownerId"
)
})

Join external column to Hibernate entity using native SQL

I have a (simplified) table structure that looks something like that:
customer table:
id name
-------------------
1 customer1
alias table:
customer_id alias
-------------------------------
1 customer one
1 customer uno
When I run the following query I easily get the list of aliases per customer:
select * from customer_alias where customer_id=1;
I would like to use this query in my hibernate to populate a list of type String. I tried using #Formula as follows:
#Entity
#Table(name = "customer")
public class Customer {
#Id
#Column(name = "id")
#GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
#Column(name="name")
private String name;
#Formula("(select alias from customer_alias where customer_id = id)")
private List<String> aliases;
// Getters, setters, etc...
}
It didn't work and I got this exception:
Could not determine type for: java.util.List, at table: customer, for columns: [org.hibernate.mapping.Formula( (select alias from customer_alias where customer_id = id) )]
Is there anyway to achieve this? Doesn't have to be with #Formula of course. Any reasonable way would be great.
Here is an SQLFiddle of my example
You could use #ElementCollection for having a List of related aliases without the need to map the whole entity:
#ElementCollection
#CollectionTable(name = "customer_alias", joinColumns = #JoinColumn(name = "customer_id") )
#Column(name = "alias")
private List<String> aliases;
See also:
Difference between #OneToMany and #ElementCollection?
I think you don't want to use OneToMany annotation as the second table is just a list of strings you want to find something more elegant that would not require me to create another entity.
You can use #ElementCollection as below:
#Entity
#Table(name="college")
class College implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="college_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int collegeId;
#Column(name="name")
private String collegeName;
#ElementCollection
#CollectionTable(name="student", joinColumns=#JoinColumn(name="college_id"))
#Column(name="student_name")
private Set<String> students;
public College() {
}
public Set<String> getStudents() {
return students;
}
public void setStudents(Set<String> students) {
this.students = students;
}
public int getCollegeId() {
return collegeId;
}
public void setCollegeId(int collegeId) {
this.collegeId = collegeId;
}
public String getCollegeName() {
return collegeName;
}
public void setCollegeName(String collegeName) {
this.collegeName = collegeName;
}
#Override
public String toString() {
return "College [collegeId=" + collegeId + ", collegeName=" + collegeName + ", students=" + students + "]";
}
}
I don't think #Formula annotation supports collection it can only be applied for single-valued properties. Can't say if if there exists any tweak.

JPA CriteriaQuery join three tables not directly navigable

i need to translate this sql query to jpa criteria:
SELECT tbl1.id_t1, tbl2.name, tbl3.name, tbl4.symbol, tbl1.limit, tbl1.value, tbl1.uncertainty
FROM table_1 AS tbl1
JOIN table_2 AS tbl2 ON tbl2.id_t2=tbl1.id_t2
JOIN table_3 AS tbl3 ON tbl3.id_t3=tbl1.id_t3
JOIN table_4 AS tbl4 ON tbl4.id_t4=tbl1.id_t4
WHERE (tbl2.id_l=1 AND tbl3.id_l=1) AND tbl1.id_s=1;
my mapping between pojo and database table are as follows:
Table_1
#Entity
#Table("table_1")
public class Table1 {
#Id
#Column(name="id_t1")
private Long idRowT1
#ManyToOne
#JoinColumn(name="id_t2")
private Table2 tbl2;
#ManyToOne
#JoinColumn(name="id_t3")
private Table3 tbl3;
#ManyToOne
#JoinColumn(name="id_t4")
private Table4 tbl4;
#Column(name="limit")
private String limit;
#Column(name="value")
private String value;
#Column(name="uncertainty")
private String uncertainty;
// getter and setter
}
Table_2
#Entity
#Table("table_2")
public class Table2 {
#Id
#Column(name="id_t2")
private Long idT2;
// getter and setter
}
Table_2_lang
#Entity
#Table("table_2_lang")
#IdClass(Table2LangPK.class)
public class Table2Lang {
#Id
#Column(name="id_t2")
private Long idT2;
#Id
#Column(name="id_l")
private Lang l;
#Column(name="name")
private String name;
// getter and setter
}
Table_3
#Entity
#Table("table_3")
public class Table3 {
#Id
#Column(name="id_t3")
private Long idT3;
// getter and setter
}
Table_3_lang
#Entity
#Table("table_3_lang")
#IdClass(Table3LangPK.class)
public class Table3Lang {
#Id
#Column(name="id_t3")
private Long idT3;
#Id
#Column(name="id_l")
private Lang l;
#Column(name="name")
private String name;
// getter and setter
}
Table_4
#Entity
#Table("table_4")
public class Table4 {
#Id
#Column(name="id_t4")
private Long idT4;
#Column(name="name")
private String name;
// getter and setter
}
To send data from business layer to front-end i'm using value objects defined as follows:
Simple entity
public class SimpleEntityVO {
private Long entityId;
private String name;
// getter and setter
}
Complex Entity
public class SimpleEntityVO {
private Long entityId;
private SimpleEntityVO tbl2VO;
private SimpleEntityVO tbl3VO;
private SimpleEntityVO tbl4VO;
// ... other field of table_1
// getter and setter
}
In my EJB i need to implement a method that return a list of ComplexEntityVO starting from Table_1
...
private CriteriaBuilder cB = eM.getCriteriaBuilder();
public List<ComplexEntityVO> findAll(Long id_s, Long id_l) {
CriteriaQuery<ComplexEntityVO> cQ = cB.createQuery(ComplexEntityVO.class)
Root<Table1> tbl1Root = cQ.from(Table1.class);
// UPDATE BEGIN
Root<Table2Lang> tbl2Root = cQ.from(Table2Lang.class);
...
Selection<SimpleEntityVO> sESTbl2 = cB.construct(SimpleEntityVO.class, tbl2Root.get(Table2Lang_.id_t2), tbl2Root.get(Table2Lang_.name));
// The selection for table_3_lang and table_4 are the same
// UPDATE END
TypedQuery<ComplexEntityVO> tQ = eM.createQuery(cQ);
}
...
To achieve the results i've tried with join betwen Table1 and Table2Lang, tried with selection like the one exposed below
`Selection<SimpleEntityVO> sES = cB.construct(SimpleEntityVO.class, ...);`
using Root for lang table, tried with solution exposed here
https://community.oracle.com/message/10795956#10795956
but when i try to execute this statement
`cQ.select(cB.construct(ComplexEntityVO.class, id_t1, SimpleEntityVO)`
or this
`cQ.multiselect(...)`
i get the: IllegalArgumentException
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: , near line 1, column 64
[select new com.example.vo.ComplexEntityVO(generatedAlias0.id_t1,
new com.example.labims.vo.SimpleEntityVO(generatedAlias1.table2.id_t2, generatedAlias1.name),
new com.example.vo.SimpleEntityVO(generatedAlias2.table_3.id_t3, generatedAlias2.name),
new com.example.vo.SimpleEntityVO(generatedAlias3.id_t4, generatedAlias3.name),
generatedAlias0.limit, generatedAlias0.value, generatedAlias0.uncertainty)
from com.example.Table1 as generatedAlias0,
com.example.model.Table2Lang as generatedAlias1,
com.example.model.Table3Lang as generatedAlias2,
com.example.model.Table4 as generatedAlias3
where ( generatedAlias0.id_s=:param0 ) and ( ( generatedAlias1.lang.id_l=:param1 ) and ( generatedAlias2.lang.id_l=:param1 ) )]
From the cause of execption understanded that i can't instanciate new object inside select or multiselect statement, but i don't find a way to achieve the original SQL query using criteria API.
UPDATE
i've added an excerpt of what i've tried to achieve the result between //UPDATE BEGIN and //UPDATE END
I think make hibernate show sql == true
and take query by console,test showed query your databases and find error hbernate not generate query correct
There are two approaches to solve this problem.
Add a constructor method to ComplexEntityVO like this:
public ComplexEntityVO(Long id, Long simpleId2, String simpleName2 /* etc ... */) {
this.simpleEntityVo = new SimpleEntityVO(simpleId2, simpleName2);
// etc for other associations
}
add a ProjectionList to your query, return a List<Object[]> instead of a List<ComplexEntityVO> and then iterate over the results like so
for(Object[] o: results) {
ComplexEntityVO cvo = new ComplexEntityVO((Long)o[0]);
new SimpleEntityVO vo2 = new SimpleEntityVO((Long) o[1], (String) o[2]);
cvo.setTbl2VO(vo2);
// ... etc for other associations
}
Although the second is uglier I would prefer it, since it is more flexible, and allows more opportunities for debugging, logging etc.
See AliasToBeanResultTransformer(MyDTO.class) fails to instantiate MyDTO

Join Table and OneToMany relation in Hibernate

I created two entities for the tables HOBBY and STUDENT, but I have difficulties to retrieve the information I need from the Join Table.
This is the schema:
STUDENT STUDENT_HOBBY HOBBY
-------- ----------- --------
id ------------------ student_id
name hobby_id ---------- id
lastname hobby_name
--------- ---------- --------
where
Student to student_hobby = one to many
Hobby to student_hobby = one to many
(that means a student may have many hobbies and a hobby can belong to more than one student)
This is the Student entity class:
#Entity
#Table(name="STUDENT")
public class Student {
#OneToMany
#JoinTable(name="student_hobbies", joinColumns=#JoinColumn(name="student_id"),
inverseJoinColumns=#JoinColumn(name="hobby_id"))
private Collection<Hobby> hobbies;
#Id
#Column(name="ID")
#GeneratedValue
private Integer id;
#Column(name="NAME")
private String name;
#Column(name="LASTNAME")
private String lastName;
// Getters and setters here
}
This is the Hobby entity class:
#Entity
#Table(name="HOBBY")
public class Hobby {
#OneToMany
#JoinTable(name="student_hobbies", joinColumns=#JoinColumn(name="hobby_id"),
inverseJoinColumns=#JoinColumn(name="student_id"))
private Collection<Student> students;
#Id
#Column(name="ID")
#GeneratedValue
private Integer id;
#Column(name="HOBBY_NAME")
private String hobby_name;
// Getters and setters here
}
Now I would like to implement the following DAO, but I don't know exactly how to do:
public interface MyDAO {
public void addHobbyForStudent(int student_id, int hobby_id);
public void RemoveHobbyForStudent(int student_id, int hobby_id);
}
Should I create an other entity class for the Join Table? Could someone give me some indication on the way to follow?
You can create an entity class for the join table, but you don't need to and you probably shouldn't. This will just create more code to maintain. You should create an entity for the join table if there is data in the join table you need to query. EG: if there was a start_time or something in the join table and you wanted to be able to see the start_time.
You should be using the #ManyToMany annotation when you're avoiding a join table entity. The documentation I linked to gives some good examples of how to do this:
Example 1:
// In Customer class:
#ManyToMany
#JoinTable(name="CUST_PHONES")
public Set<PhoneNumber> getPhones() { return phones; }
// In PhoneNumber class:
#ManyToMany(mappedBy="phones")
public Set<Customer> getCustomers() { return customers; }
Example 2:
// In Customer class:
#ManyToMany(targetEntity=com.example.PhoneNumber.class)
public Set getPhones() { return phones; }
// In PhoneNumber class:
#ManyToMany(targetEntity=com.example.Customer.class, mappedBy="phones")
public Set getCustomers() { return customers; }
Example 3:
// In Customer class:
#ManyToMany
#JoinTable(name="CUST_PHONE",
joinColumns=
#JoinColumn(name="CUST_ID", referencedColumnName="ID"),
inverseJoinColumns=
#JoinColumn(name="PHONE_ID", referencedColumnName="ID")
)
public Set<PhoneNumber> getPhones() { return phones; }
// In PhoneNumberClass:
#ManyToMany(mappedBy="phones")
public Set<Customer> getCustomers() { return customers; }

How to make a query to get results based on two othe relations in JPA? (kinda join three tables)

I have a Post class which is like below and it has a one-to-many relation with Users (people who can see this post) and also it has the same kind of relation (one-to-many) with Groups, now I want to get all the posts by a JPA Query based on Users and Groups, how should I write the JPA Query for this?
/* Post */
public class Post extends Model {
private String title;
private String text;
#OneToMany
#JoinTable(
name="tbl_post_users",
inverseJoinColumns={#JoinColumn(name="userId")},
joinColumns={#JoinColumn(name="postId")}
)
public List<User> users;
#OneToMany
#JoinTable(
name="tbl_post_groups",
inverseJoinColumns={#JoinColumn(name="groupId")},
joinColumns={#JoinColumn(name="postId")}
)
public List<Group> groups;
public static List<Post> GetPosts(){
// JPA Query here
}
}
/* User */
public class User extends Model {
#Id
private int id;
private String name;
private String email;
}
/* Group */
public class Group extends Model {
#Id
private int id;
private String title;
private int ownerId;
}
So I want to write the query so that I can get a list of all posts where user is {user} or group is {group}
select distinct p from Post p
left join p.users user
left join p.groups group
where user = :user
or group = :group
Read http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#queryhql-joins

Categories

Resources