Select only JPA Collection members meeting condition - java

I'm trying to select entries for Entity A where all of the children in its collection of CReference entities meet a condition. The query I currently have only requires the conditions to be met on at least one of the members.
Current Query
This query currently selects all objects of type A where at least one of the items in its c_references class
SELECT a FROM A a INNER JOIN FETCH a.c_references c_refs INNER JOIN FETCH c_refs.c_reference c_ref WHERE (c_ref.flag_one=TRUE AND c_ref.flag_two=TRUE)
Classes
Class A
#Entity
public class A{
#Id
private UUID a_uuid;
#OneToMany(fetch = FetchType.EAGER)
#JoinColumn(name = "owning_a_uuid")
private List<CReference> c_references;
}
Class CReference
#Entity
// This class keeps references to all of the A objects that have referenced a C object
public class CReference{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long c_reference_id;
#OneToOne
private A a_referencing_c;
#OneToOne
private C c_reference;
}
Class C
#Entity
#Cacheable
public class C{
#Id
private UUID c_uuid;
private Boolean flag_one = false;
private Boolean flag_two = false;
}

Try this:
SELECT a FROM A a
WHERE NOT EXISTS(
SELECT c_refs
FROM CReference c_refs
INNER JOIN c.c_reference c_ref
WHERE
c_refs.a_referencing_c = a
AND (c_ref.flag_one = FALSE OR c_ref.flag_two = FALSE)
)

Related

Reference properties of null referenced object in HQL

Here I have two Entity class.
#Table(name = "AC_ACCOUNT_MASTER")
public abstract class Account implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "a_name")
private String name;
}
And
#Table(name = "AC_VOUCHER_MASTER")
public class Voucher implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Double amt;
#ManyToOne
private Account drAc;
#ManyToOne
private Account crAc;
}
There are 10 rows in AC_VOUCHER_MASTER table, where 4 drAc data are null in AC_VOUCHER_MASTER table.
session.createQuery("select v.id, v.amount, v.drAc.id, v.crAc.id from Voucher v").list();
The above query returns me 10 result (although 4 drAc are null). But when I put name refernce (v.drAc.name), it returns only those rows (6 rows) that drAc is not null.
"select v.id, v.amount, v.drAc.id, v.drAc.name, v.crAc.id , v.crAc.name from Voucher v"
What Should I do now ? Is there to use coalesce() or something else ?
Use a left join:
select v.id, v.amount, drAc.id, drAc.name, crAc.id , crAc.name
from Voucher v
left join v.drAc drAc
left join v.crAc crAc

Hibernate: separate sql query for every collection

I have a Person class that has a collection of Contacts. Everything works ok, I get the list of persons with their contacts. However, in log I see that a separate query is made to read collection of every person. That is too bad.
How to make hibernate make a join to read all the data in one query? I use JPA.
This is the person class:
#Entity
#Table(name = "tbl1")
public class PersonItem implements Serializable{
#Id
#Column(name="col1")
private String guid;
.....
#ElementCollection(targetClass = ContactItem.class,fetch=FetchType.EAGER)
#CollectionTable(name="tbl2",joinColumns=#JoinColumn(name="col2"))
private List<ContactItem> contacts;
....
}
This is the contact class
#Embeddable
#Table(name = "tbl2")
public class ContactItem implements Serializable {
#Column(name="col1")
private String guid;
#Column(name="col3")
private String info;
}
This is the way I get the list of persons:
Query query = em.createQuery("Select p from PersonItem p WHERE p.guid IN (:guids)");
query.setParameter("guids", guids);
List<PersonItem> list=query.getResultList();
And this what I see in log (I have three persons in DB):
Hibernate: select personitem0_.col1 as col1_0_, personitem0_.col4 as col2_0_, personitem0_.col2 as col3_0_, personitem0_.col3 as col4_0_ from tbl1 personitem0_ where personitem0_.col1 in (? , ? , ?)
Hibernate: select contacts0_.col2 as col1_1_0_, contacts0_.col1 as col2_1_0_, contacts0_.col3 as col3_1_0_ from tbl2 contacts0_ where contacts0_.col2=?
Hibernate: select contacts0_.col2 as col1_1_0_, contacts0_.col1 as col2_1_0_, contacts0_.col3 as col3_1_0_ from tbl2 contacts0_ where contacts0_.col2=?
Hibernate: select contacts0_.col2 as col1_1_0_, contacts0_.col1 as col2_1_0_, contacts0_.col3 as col3_1_0_ from tbl2 contacts0_ where contacts0_.col2=?
Please, begin from a more simple mapping. Use plural names, and column prefixes.
#Entity
#Table(name = "persons")
public class Person {
#Id
#Column(name = "f_guid")
private String guid;
#OneToMany(mappedBy = "person", fetch = FetchType.EAGER)
private List<Contact> contacts;
}
#Entity
#Table(name = "contacts")
public class Contact {
#Id
#Column(name = "f_guid")
private String guid;
#Column(name = "f_info")
private String info;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "fk_person")
private Person person;
}
Person is associated to contacts by a foreign key fk_person in the contacts table.
Update
Looks like JPQL overrides a default fetching strategy. You need to specify a fetch explicitly
select p from PersonItem p left join fetch p.contacts WHERE p.guid IN (:guids)
If you have duplicates, cause of joins, you can use distinct
select distinct p from PersonItem p left join fetch p.contacts WHERE p.guid IN (:guids)
Try #Fetch on your relation.
Also i would suggest to use #OneToMany relation int this case
#OneToMany(mappedBy = "person", fetch = FetchType.EAGER)
#Fetch(FetchMode.JOIN) //You can use SUBSELECT as well
private List<ContactItem> contacts;
You can read more about fetching strategies here
fetch-“join” = Disable the lazy loading, always load all the collections and entities.
fetch-“select” (default) = Lazy load all the collections and entities.
batch-size=”N” = Fetching up to ‘N’ collections or entities, Not record.
fetch-“subselect” = Group its collection into a sub select statement.

How to make Hibernate criteria to bring only needed fields

I have next classes:
#Entity
#Table(name="A")
public class A implements Serializable{
#Id
#Column(name="a_id")
private long aId;
#ManyToOne
#JoinColumn(name="b_id")
private B b;
}
#Entity
#Table(name="b")
public class B implements Serializable{
#Id
#Column(name="b_id")
private long bId;
#Column(name="b_name")
private String name;
#Column(name="b_age")
private String age;
#OneToMany(mappedBy="b")
private Set<A> a;
}
I have getters and setters for this classes.
when I try execute next Criteria
session.createCriteria(A.class, "a_table")
.createAlias("a_table.b", "b_table")
.add(Restrictions.eq("b_table.age", "11"))
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
In SQL generated by hibernate I have all fields from B (I mean field "name" too).
How I can make to Hibernate bring only needed fields.
In case that in criteria exists many aliases to many tables, it can increase execution time.
Thank you.
Try using projections. Maybe something like this:
Criteria cr = session.createCriteria(User.class)
.setProjection(Projections.projectionList()
.add(Projections.property("id"), "id")
.add(Projections.property("Name"), "Name"))
.setResultTransformer(Transformers.aliasToBean(User.class));
List list = cr.list();

How to get child table rows using parent table ID?

I have two tables: Organization(Parent) and Department(Child).
There is One to Many relationship, and is mentioned in Organization table only.
#Entity
#Table(name="TBL_STD_ORGANIZATION")
public class Organization implements Serializable {
#Id
#GeneratedValue
#Column(name="FLD_ORG_ID")
private Long organizationId;
#Column(name="FLD_ORG_NAME")
private String orgName;
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
private java.util.List<Department> listOfDepartMents = new java.util.ArrayList<Department>();
}
Below is Department Class:
#Entity
#Table(name="TBL_STD_DEPARTMENT")
public class Department implements Serializable {
#Id
#GeneratedValue
#Column(name = "FLD_DEPARTMENT_ID")
private Long departmentId;
#Column(name = "FLD_DEPARTMENT_NAME")
private String departmentName;
}
I wrote relationship in Parent table, because of it hibernate creates third table.
Now, I have to retrieve departments start with "sa" keyword and in specific organization.
So I want the HQL or SQL query query. I am not getting it how to write such complex query.
Any suggestions?
I'm fairly certain the HQL/JPQL would be:
SELECT d FROM Organization o JOIN o.listOfDepartMents d WHERE d.departmentName LIKE "sa%"

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