Add filter on oneToMany mapped table in hibernate/Spring - spring

I am using hibernate4 and spring3.1 in my current project.
I have two tables with one to many mapping. I am using annotation based mapping.
Mappings are done like this :
public class TableA {
#Id
private Long id;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "sample_id")
private Set<TableB> tableBList;
// setter getter
}
public class TableB{
#Id
private Long id;
private Long sample_id;
private Date added_date;
}
When I fired query like this :
String hql = "FROM TableA WHERE id = 5";
return sessionFactory.getCurrentSession().createQuery(hql).list();
It will return all the rows from TableB which are mapped for id =5.
But I want to add one more condition like added_date = XXXX.
Is it possible to add filter in query or by any other way on column added_date ?

Yes it is possible from the query :
look at the hql documentation : http://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html_single/#queryhql
You want something like
String hql = "select a from TableA as a inner join a.tableBList as b WHERE a.id = :id and b.added_date > :after";
Query q = sessionFactory.getCurrentSession().createQuery(hql);
q.setParameter("id", 5);
q.setParameter("after", date);
q.list();

Related

JPQL: Warning: HHH000183, Join query between two entities in different folders

What is the correct way to create Join query between two entities in different folder without using eg. #OneToOne relation ?
I have two entities
First in entity/folder1
package com.test.test.test.model.entity.folder1;
#Entity
#Table(name = "table1")
public class Table1 {
#Column(name = "code", length = 6, updatable = false)
private String code;
}
And second entity in entity/folder2
package com.test.test.test.model.entity.folder2;
#Entity
#Table(name = "table2")
public class Table2 {
#Column(name = "code", length = 6, updatable = false)
private String code;
#Column(name = "postCode", length = 6, updatable = false)
private String postCode;
}
Query in Repository (Query working but return empty response):
#Query("""
SELECT t1 FROM Table1 t1
JOIN com.test.test.test.model.entity.folder2.Table2 t2 ON t1.code = t2.code
WHERE t2.postCode <> ''
""")
Optional<Customer> test1Query();
Warning:
HHH000183: no persistent classes found for query class: SELECT t1 FROM Table1 t1
JOIN com.test.test.test.model.entity.folder2.Table2 t2 ON t1.code = t2.code
WHERE t2.postCode <> ''
I spent a lot of time to fix this but i dont know how.
Thanks for help
Because this repository interface only Customer table use.
For without using eg. #OneToOne relation, you can try use: EntityManager or Criteria API

JPA mapping :Primary key column of one table to non Pk/Fk column of another table

#Entity
#Table(name = "TableA")
public class TableAEntity{
#Id
#Column(name = "RUL_ID"
private Integer rulId;
#Column(name = "COMMENT"
private Integer comment;
#OneToOne
#JoinColumn(name = "RUL_ID" referencedColumnName ="PRNT_ID", insertable=false, updatable=false)
private TableBEntity tableB;
//GETTERS AND SETTERS
}
#Entity
#Table(name = "TableB")
public class TableBEntity{
#Id
#Column(name = "ADD_ID"
private Integer addID;
#Column(name = "PRNT_ID"
private Integer prntId;
//GETTERS AND SETTERS
}
There are 2 DB tables.
TableA with primary key as rulId.
TableB with primary key as addID.
I have to implement a customized JOIN query using JPA native query.
Java Code is:
StringBuilder querySql = "select a.rulId, b.prntId from TableA a JOIN TableB b ON a.rulID = b.prntId"
Query tabQuery = entityManager.createNativeQuery(querySql.toString, TableAEntity.class)
List<TableAEntity> entityList = tabQuery.getResultList();
How to establish this OneToOne(TableA:TableB) relationship when they are not linked with any key(pk/fk).
I am unable to map ResultList to my entity class.Primary key of TableA "rulId" always gets linked to PrimaryKey of TableB "addId", wherein I want to get it associated to "prntId".
Can anyone please help on this.
A couple of things to note:
For JPA query, you have to use createQuery (createNativeQuery is for SQL queries);
#Table(name=...) will define the name of the table in the database but not when you write a JPQL query. For that you can use #Entity(name="..."). In your case, it should be #Entity(name="TableA");
The return value of the query is two fields, not TableAEntity. So passing it as parameter to createQuery is wrong;
It's weird to return a.id and b.id. If you want the entities, you can return a and b.
If there is an association between TableA and TableB, for example:
#Entity(name = "TableA")
public class TableAEntity {
...
#OneToOne
#JoinColumn(referencedColumnName ="PRNT_ID", insertable=false, updatable=false)
public TableBEntity tableB;
}
then you can run the following query:
String jpqlQuery = "from TableA a join fetch a.tableB b";
List<TableAEntity> entityList = entityManager.createQuery(jpqlQuery, TableAEntity.class).getResultList()
entityList.foreach( tableAEntity -> {
TableBEntity tabB = tableAEntity.tableB;
});
If there is no association between TableA and TableB:
String jpqlQuery = "select a, b from TableA a JOIN TableB b ON a.rulID = b.prntId";
List<Object[]> entityList = entityManager.createQuery(jpqlQuery).getResultList()
entityList.foreach( row -> {
TableAEntity tabA = (TableAEntity) row[0];
TableBEntity tabB = (TableBEntity) row[1];
});
But if you really just need the ids, this will work too:
String jpqlQuery = "select a.rulId, b.prntId from TableA a JOIN TableB b ON a.rulID = b.prntId";
List<Object[]> entityList = entityManager.createQuery(jpqlQuery).getResultList()
entityList.foreach( row -> {
Integer tabAId = (Integer) row[0];
Integer tabBId = (Integer) row[1];
...
});
Note that you can change the select and mix the two approaches.
But because there is an association between TableAEntity and TableBEntity, you could rewrite all this as:
String jpqlQuery = "from TableA";
List<TableAEntity> entityList = entityManager.createQuery(jpqlQuery,
TableAEntity.class).getResultList()
entityList.foreach( entity -> {
TableAEntity tabA = entity;
TableBEntity tabB = entity.getTableB();
...
});
With or without the association, you can return from the select clause all the combinations of values you need:
select a, b.addID from ...
select a, b from ...

How to do Custom join with Child Entity for a field in JPA?

Hi i have below two entity tables where LOANS is my parent class and DDL Table class is child . The join is custom join . I have other child tables which am able to join correctly. But for this DDL table i want to try a custom join . I am not sure how i can achieve it . The Oracle Query i am trying to achieve is below . How i can do this . Open for Suggestions if this not the correct way of doing it .
Oracle Query
select dt.DESCRIPTION
from LOANS l,ddl_table dt
where
dt.table_name='master' and dt.field_name='mc'
and SUBSTR(dt.DESCRIPTION, 2, 1) = l.MC_TYPE
and l.LOAN_ID = :LOAN_ID
Parent Entity
#DynamicUpdate
#Data
#NoArgsConstructor
#ToString
#Table(name = "LOANS")
#Entity
public class Loans {
#Id
#Column(name = "LOAN_ID")
private Long loanId;
#OneToOne(cascade = CascadeType.ALL)
#WhereJoinTable(clause = "table_name='master' and field_name='type'")
private DDLTable ddlTable;
// Other child tables.
}
DDL Table Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
#Table(name = "DDL_TABLE")
#Entity
public class DDLTable {
#Id
#Column(name = "TABLE_NAME")
private String tableName;
#Id
#Column(name = "FIELD_NAME")
private String fieldName;
#Column(name = "DESCRIPTION")
private String description;
#Column(name = "FILTER_TYPE")
private String filterType;
}
Do you want to (1) establish an association between Loans and DdlTable, or (2) simply execute the query you posted?
If the former, then only the dt.table_name='master' and dt.field_name='mc' and SUBSTR(dt.DESCRIPTION, 2, 1) = l.MC_TYPE part becomes the join clause. You will then be able to call em.find(Loans.class, loanId) and the Loans.ddlTable will be populated in the result. You'll want sth along the lines of:
#OneToOne
#JoinFormula(formula = "SELECT SUBSTR(dt.DESCRIPTION, 2, 1) FROM ddl_table dt WHERE dt.table_name='master' and dt.field_name='mc'", referencedColumnName = "MC_TYPE")
If the latter, there's no need for the Loans.ddlTable field at all, your query can be translated easily into JPQL:
SELECT dt.description
from Loans l, DdlTable dt
where
dt.tableName='master' and dt.fieldName='mc'
and SUBSTRING(dt.description, 2, 1) = l.mcType
and l.loanId = :LOAN_ID
As a side note, I'd think about mapping SUBSTRING(dt.description, 2, 1) as a virtual column in your DB to make the entity mapping easier. Perhaps even a dedicated view with dt.tableName='master' and dt.fieldName='mc'. You could index SUBSTRING(dt.description, 2, 1) for faster lookup.

i wish to find a unique record which matches mutiple column values supplied at once

i have a spring application where i wish to find a unique record which matches mutiple column values supplied at once. How should i write my own custom method for it in an interface implementing CrudRepository
below is the model and the interface
#Entity
#Table(name = "tenant_subscriptions")
public class TenantSubscriptions {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "userId")
private Long userId;
#Column(name = "service_id")
private Long serviceId;
#Column(name = "feature_id")
private Long featureId;
#Column(name = "subfeature_id")
private Long subfeatureId;
#Column(name = "status")
private String Status;
#Column(name = "subscription_id")
private String SubscriptionId;
public interface TenantSubscriptionsRepository extends CrudRepository<TenantSubscriptions, Long> {
}
You don't need to write your own query if it's not something super complex.
For matching multiple column values in the same table you can use query from method name.
There is two way according to documentation and Query creation:
By deriving the query from the method name directly.
By using a manually defined query.
TenantSubscriptions findByUserIdAndServiceIdAndFeatureId(Long userId, Long serviceId, Long featureId); //Hibernate will recognize your DB object and this will work (no extra thing needs to be done)
Query:
#Query(value = "SELECT u FROM User u WHERE u.status = 'ACTIVE' AND u.creationDate <= current_date()")
List<User> findUserCandidates();
Inner join query:
#Query(value = "SELECT DISTINCT u FROM User u INNER JOIN UserAccount ua ON u.id = ua.userId WHERE ua.status = 'ACTIVE' AND ua.companyId = :companyId")
List<Bank> findBanksByCompany(Integer companyId);
You can find an entry by multiple attributes by chaining them in the interface method name. Also, Spring Data also inspects the return type of your method.
Example:
TenantSubscriptions findOneByServiceIdAndFeatureId(Long serviceId, Long featureId);
This will return the one entry that matches both attributes.
See also this answer and the Spring Data Reference Guide.

JPA Join Custom query with OneToMany

I would like to use #Query annotation to create left join query from a entity with a #OneToMany relationship.
Parent entity is :
#Entity
#Table(name="Registration")
public class Registration {
#Column(nullable = false)
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
private LocalDate effect;
#OneToMany(targetEntity=Payment.class, cascade=CascadeType.ALL,fetch = FetchType.LAZY)
#JoinColumn(name="uuid")
private List<Payment> payment;
}
Child :
#Entity
#Table(name="Payment")
public class Payment {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name="uuid", strategy = "uuid2")
#Column(columnDefinition = "BINARY(16)")
private UUID uuid;
}
For DAO, I do like below :
#Query("SELECT p FROM Registration r JOIN r.payment p WHERE r.effect = :effect")
Iterable<Payment> find(#Param("effect") LocalDate effect);
Obviously, its wrong because generated query is :
select payment1_.uuid as uuid1_9_, payment1_.amount as amount2_9_ from registration registrati0_ inner join payment payment1_ on registrati0_.uuid=payment1_.uuid where registrati0_.effect=?
while the relation table has been generated:
For me, the correct query should be something like this :
select p.* from registration r join registration_payment rp on rp.registration = r.uuid join payment p on p.uuid = rp.payment where r.effect = '2015-10-16'
What is the good query syntax please ? Actual query return en empty array.
Finally, I found a solution.
You must describe relation table with #JoinTable :
#JoinTable(
name="registration_payment",
joinColumns = #JoinColumn(name="registration"),
inverseJoinColumns = #JoinColumn(name = "payment")
)
private List<Payment> payment;
Modify #Query not needed :
#Query("SELECT p FROM Registration r JOIN r.payment p WHERE r.effect = :effect")
Generated query is :
select payment2_.uuid as uuid1_9_, payment2_.amount as amount2_9_
from registration registrati0_
inner join registration_payment payment1_ on registrati0_.uuid=payment1_.registration
inner join payment payment2_ on payment1_.payment=payment2_.uuid
where registrati0_.effect=?

Resources