Hibernate, select where foreign key is null - spring

I have entity as follows:
#Entity
#Table(name = "LORRY")
#NamedQueries({
#NamedQuery(name = "Lorry.findSuitableLorries",
query = "SELECT l from Lorry l " +
"WHERE l.order IS NULL")
})
public class Lorry {
#Id
#Column(name = "ID", length = 7)
#Pattern(regexp="[a-zA-Z]{2}\\d{5}")
#Size(min = 7, max = 7)
private String regNum;
#OneToOne(mappedBy = "lorry")
private Order order;
}
Now I need to select all rows where order id is null in the LORRY table, but it doesn't seem to work as I get empty list every time. How can I check if foreign key is null using JPQL?

Try either SELECT l from Lorry l WHERE l.order.id IS NULL or SELECT l from Lorry l left join l.order o WHERE o IS NULL

Related

Inner join with more than one OR conditions in spring boot

I am using spring boot specification and trying to execute a query that looks like this -
SELECT DISTINCT
p.name
FROM
partner p
INNER JOIN
detail d ON p.detail_id = d.id
INNER JOIN
account a ON d.account_id = a.id
OR d.crm_id = a.top_parent
OR d.crm_id = a.global_partner
I have used the code
Join<Partner, Detail> details = root.join("detail");
Join<Detail, Account> account = details.join("account");
Predicate global = cb.equal(details.get("crm_id "), account.get("top_parent"));
Predicate top = cb.equal(details.get("crm_id "), account.get("global_partner"));
account.on(cb.or(global, top));
However, it creates the query
SELECT DISTINCT
p.name
FROM
partner p
INNER JOIN
detail d ON p.detail_id = d.id
INNER JOIN
account a ON d.account_id = a.id
AND (d.crm_id = a.top_parent
OR d.crm_id = a.global_partner)
Notice the AND operator in the query...I need to replace it OR operator
Another use case I am struggling with
#Entity
public class Detail {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToMany(mappedBy = "detail", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Set<Skill> skills;
}
I am trying to generate the query below using specifications
order by (select count(s.detail_id) from skill s where detail.id = s.detail_id AND s.category is not null) desc
I have used the code below
cq.orderBy(cb.desc(cb.size(details.get("skills"))));
But the query it generates is
order by (select count(s.detail_id) from skill s where detail.id = s.detail_id) desc
Notice that I am unable to add an extra AND to the order by clause
I believe you can not change that AND.
could you change the query in the following way
SELECT DISTINCT p.name
FROM partner p INNER JOIN detail d ON p.detail_id = d.id, account a
where d.account_id = a.id
OR d.crm_id = a.top_parent
OR d.crm_id = a.global_partner
and the jpa criteria similar to
Join<Partner, Detail> details = root.join("detail");
Root<Account> account = criteria.from(Account.class);
Predicate global = cb.equal(details.get("crm_id"), account.get("top_parent"));
Predicate top = cb.equal(details.get("crm_id"), account.get("global_partner"));
Predicate byId = cb.equal(details.get("account").get("id"), account.get("id"));
Predicate or = cb.or(global, top, byId);
criteria.where(or);

how to use JPQL query to count values from a table & combine with an other table related data?

I have two tables X and Y. In Table X (Oracle sql), an unique column(primary key) code along other columns in X table.. code column may have some records in table Y which have column code_id. I want to get count of rows in table Y for code with code and other columns in table Y
and I have springboot entity called Entity I want to map results to using jpql so I want the query in JPQL:
public class Entity {
private int id;
private char code;
private String name;
// constructor & setters / getters
}
and Y table have entity Counter
public class Counter {
private int codeid;
}
I want to use jpql query equivalent to this Oracle sql query
select x.*,
(select count(*) from Y y where x.code = y.code_id) as theCount
from X x ORDER BY theCount desc , x.name asc ;
Example:
Code "A" has 3 entries, Code "B" has 2 entries and code "C" has 0 entries in table Y.
code name count
A name1 3
B name2 2
C name3 0
I did some assumptions because I miss your project code. Hope my example will fit your needs. It is not the same SQL but it is still just 1 statement producing the same type of output.
Primary entity Code having collection of Counters:
#Data
#Entity
public class Code {
#Id
private Integer id;
private String code;
private String name;
#OneToMany
#JoinColumn(name = "CODE_ID")
private List<Counter> counterList;
}
#Data
#Entity
public class Counter {
#Id
private Integer id;
}
Spring Data repository:
public interface CodeRepository extends JpaRepository<Code, Integer> {
#Query("select c.code, c.name, count(l) as amount from Code c join c.counterList l group by c.code, c.name")
List<Object[]> getSummary();
}
It returns:
A, TESTNAME1, 3
B, TESTNAME2, 2
In case following is inserted into database:
INSERT INTO CODE (ID, CODE, NAME) VALUES (1, 'A', 'TESTNAME1');
INSERT INTO COUNTER (ID, CODE_ID) VALUES (123,1);
INSERT INTO COUNTER (ID, CODE_ID) VALUES (124,1);
INSERT INTO COUNTER (ID, CODE_ID) VALUES (125,1);
INSERT INTO CODE (ID, CODE, NAME) VALUES (2, 'B', 'TESTNAME2');
INSERT INTO COUNTER (ID, CODE_ID) VALUES (234,2);
INSERT INTO COUNTER (ID, CODE_ID) VALUES (235,2);
This is how the result is produced:
codeRepository.getSummary()
.forEach(sum -> System.out.println(sum[0] + ", " + sum[1] + ", " + sum[2]));

Update multiple records in an Oracle table in JPQL

Is it possible to update several rows in one JPQL query, using CASE...WHEN...THEN expression and parameters ? It is a table of an Oracle database.
Integer param1 = .....;
Integer param2 = .....;
Integer param3 = .....;
Query query = session.createQuery("update NumberEntity i set i.value = case "
+ "when (i.id=1) then ?1"
+ "when (i.id=2) then ?2"
+ "when (i.id=3) then ?3 else 0 end");
query.setParameter(1, param1);
query.setParameter(2, param2);
query.setParameter(3, param3);
#Entity
#Table(name = "Number")
public class NumberEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idNumber", nullable = false)
private Integer id;
#Basic(optional = false)
#Column(name = "value")
private Integer value;
.......
}
I obtained this error :
java.sql.SQLSyntaxErrorException: ORA-00932: inconsistent datatypes: expected CHAR got NUMBER
The resulting SQL query is : (I have previously simplified the query, as there are 9 id to distinguish)
UPDATE Nombre SET value = CASE WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? ELSE ? END
bind => [1, null, 2, null, 3, 0, 4, 363, 5, null, 6, null, 7, 0, 8, 57314, 9, 9, 0]
I have no char column. But the "value" column is of decimal type, whereas it is an Integer in my Entity. I though I will correct this later. I don’t understand why the error deals with CHAR.
session is an object using javax.persistence package.

JPA/Hibernate map #OneToMany for Oracle hierarchical data

Say I have parent-child info in table Organization as followed:
id name parent_id
1 A 1
2 A1 1
3 A2 1
4 A11 2
With Oracle, I can get all descendants or ancestors of an organization using "start with/connect by". For example, the following sql will get all the subtree under "A" include itself (i.e. A, A1, A2, A11)
select * from Organization start with id=1 connect by nocycle prior id=parent_id;
Or this sql will get all ancestors of A11 including itself (i.e. A11, A1, A)
with o_hier as (select o.id, o.parent_id, CONNECT_BY_ISCYCLE as lvl from Organization o start with id=4 connect by nocycle prior parent_id = id) select o.* from Organization o, o_hier where o.id = o_hier.id union all select o.* from Organization o, o_hier where o.id = o_hier.parent_id and o_hier.lvl = 1;
Now I want to map this table into OrganizationEntity like this:
#Entity
#Table(name = "Organization")
public class OrganizationEntity {
//getter/setter omitted for readability
#Id
#Column(name = "ID")
private String id;
#Column(name = "NAME")
private String name;
#ManyToOne(fetch = FetchType.LAZY)
#???
List<OrganizationEntity> descendants = new ArrayList<>();
#ManyToOne(fetch = FetchType.LAZY)
#???
List<OrganizationEntity> ancestors= new ArrayList<>();
}
I'm aware of possible performance issue, but can we map something like this using Hibernate/JPA?
This is a tricky one. You can use standard parent and childern mappings.
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ID")
OrganizationEntity parent;
#OneToMany(fetch = FetchType.LAZY)
#mappedBy(mappedBy="parent")
List<OrganizationEntity> childern;
And then use standard tree taversals algorithms to get all the ancestors (simple while loop) or all the descendants (some DFS variant, usually preorder).
Performace wise this wound be very slow.
Other, and better idea is just do the traversals within the database with CONNECT BY and then map the result set to objects. You can do that with pure JPA calls or Hibernate specific calls.

LINQ intersect?

I have two tables in form of these clases
public class Movie
{
private int MovieID;
private string Title;
}
public class transactions
{
private int TransactionID;
private int MovieID;
}
so first table contains ALL movies 2nd contains movies which are RENTED
How do I select ALL movies that are left in the store , ie not rented and are available. Tried soething like:
var moviesavailable =
(from m in db.Movies
select m.MovieID ).Intersect
(from trans in db.Transactions
select trans.MovieID)
but not working...
First way to do it is go over all movies and for each look if there is no transaction with the same MovieID:
db.Movies.Where(m => !db.Transactions.Any(t => t.MovieID == m.MovieID))
Second way is to make left join. We join all rows from Movies and their equivalent rows from Transactions. If there is no row in Transactions for a row in Movies, then for this row the transaction is null (DefaultIfEmpty):
from m in db.Movies
join t in db.Transactions on m.MovieID equals t.MovieID into g
from t in g.DefaultIfEmpty()
where t == null
select m.MovieID

Resources