JPA repository queries by function name for not equals - spring

I'm trying to write a query by function name available in Spring (JPA). I need something like this select * from table where col1=x AND col2=y AND col3 <> z. Would the following function name be equivalent?
findByCol1AndColb2ndCol3IsNot(....)

findByCol1AndCol2AndCol3Not -> you just need to remove the "Is" . The following page lists all the possible keywords:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation

Related

Using multiple keywords with LIKE in Postgresql through Spring Data JPA

I need to define a JPA query that translates as:
SELECT
*
from
items_table
where
lower(CONCAT(item_id,' ', color,' ',details,' ')) like all ('{"%blue%", "%plastic%"}') and
store='Main' and
status='In Stock' and
item_type='Container';
the parameter list in all will be an input along with the store, status and item_type from the front end.
I understand it's the first WHERE condition you're having a problem with. If a String[]-typed parameter doesn't cut it, try using this approach, hopefully the LIKE ALL will pass through to the generated query - sth like:
#Query("SELECT i FROM Item i WHERE LOWER(CONCAT(...)) LIKE ALL :terms AND ...")
List<Item> findByTerms(TypedParameterValue terms, ...)
itemRepository.findByTerms(new TypedParameterValue(StringArrayType.INSTANCE, terms), ...)
If it turns out JPA doesn't like LIKE ALL, you'll have to keep using the native query.

Spring Data JPA #Query with Specification

I have a requirement to create a REST api. Api allows user to provide dynamic search criteria in URL. For example, let say I have NOTES table with column as Note_ID, NOTE_TEXT, STATUS, PERSON_ID. This table is used to keep notes of every person.
Now I want my REST api to be as https://server:host/MyApi/Notes?search=NoteText=='My Java adventure'. API should provide all notes having NOTE_TEXT as 'My Java adventure'. Similarly user can provide status also in url and also he can use operators as LIKE. I was able to do it via rsql parser as mentioned in https://www.baeldung.com/rest-api-search-language-rsql-fiql
Now I have additional requirement that based on user security person_id filter should be applied on query automatically.
I found that we can't have findBy method which can take Specification, Pageable and extra personId. For example I can't have a repository function as
findByPersonId(Specification spec, Pageable page, Long personId);
I thought of using SpEL to use it, but then I found that if we use #Query annotation on findBy method, Specifications are ignored.
Seems like there is no way I can have Specification and #Query both. I need to add more clauses using specification only. In reality my where clause is very complex which I have to append and getting it with Specification seems to be difficult. Its something like
Select * from NOTES where exists (select 'x' from ABC a where n.person_id = a.person_id)
Is there a way I can write #Query and also have Specification working on top of it?
Ideally I have achieve a query like
select * from test.SCH_FORUM_THREAD t
where exists (select 'x' from test.FORUM_THREAD_ACCESS fta, school.SCH_GROUP_PERSON gp
where gp.GROUP_ID = fta.GROUP_ID
and t.THREAD_ID = fta.THREAD_ID
and gp.PERSON_ID = :personId)
or exists (select 'x' from test.FORUM_THREAD_ACCESS fta
where fta.THREAD_ID = t.THREAD_ID
and fta.PERSON_ID = :personId);
So there are two exists clauses with or condition. I was able to make second exists by following How to write query(include subquery and exists) using JPA Criteria Builder
Now struggling with first exists as it has join also. Any idea how to do that with Specification.
Also as there are two exists, does that mean I need two specifications. Can I achieve it in one specification.
I was able to resolve it by creating a complex specification code. Something like
#Override
public Predicate toPredicate(Root<ForumThread> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
Subquery<ForumThread> subQuery = query.subquery(ForumThread.class);
Root<ForumThread> subRoot = subQuery.from(ForumThread.class);
Join<ForumThreadAccess, GroupPerson> fragpjoin = subRoot.join("groupPersons");
Predicate threadPredicate = builder.equal(root.get("threadId"), subRoot.get("threadId"));
Predicate personPredicate = builder.equal(fragpjoin.get("personId"), personId);
subQuery.select(subRoot).where(threadPredicate, personPredicate);
Predicate existsGroupPredicate = builder.exists(subQuery);
Subquery<ForumThreadAccess> subQuery1 = query.subquery(ForumThreadAccess.class);
Root<ForumThreadAccess> subRoot1 = subQuery1.from(ForumThreadAccess.class);
Predicate threadPredicate1 = builder.equal(root.get("threadId"), subRoot1.get("threadId"));
Predicate personPredicate1 = builder.equal(subRoot1.get("personId"), personId);
subQuery1.select(subRoot1).where(threadPredicate1, personPredicate1);
Predicate existsPersonPredicate = builder.exists(subQuery1);
return builder.or(existsGroupPredicate,existsPersonPredicate);
}
To make it work your entities should also have proper #OneToMany and #ManyToMany in place.
Thanks

Partial select of left joined table with doctrine query builder

When querying one table using the doctrine query builder a partial select can be written like this:
$queryBuilder = $this->createQueryBuilder('person');
$queryBuilder->addSelect('partial person.{id, name}');
How can one write a partial select be written for a left joined table? I tried something like this, but can't figure out the correct syntax:
$queryBuilder = $this->createQueryBuilder('person');
$queryBuilder->join('person.address');
$queryBuilder->addSelect('partial person.{id, name} person.address.city'); // ???
My goal would be to select only parts of the Person and the Address object when executing the query to be more memory efficient.
Your syntax is off for your join operation. You have to give an alias when using join. From there, you can just use the same syntax to query your partial Address object:
// In a method of PersonRepository
$qb = $this->createQueryBuilder('person')
->select(['partial person.{id, name}', 'partial address.{id, city}'])
->join('person.address', 'address');
Notice that I added id to the fields retrieved for Address. If you don't, Doctrine will give you the following error:
Error: The partial field selection of class Path\To\Entity\Address must contain the identifier
As a side note, you said you wanted to write this select for a left joined table. If you want to perform a LEFT JOIN, you need to use leftJoin instead of join (the signature of both methods is the same).

using list to map tables in HQL

Im using HQL to create a query in a report application, my query looks like this:
from Identity i, Bundle b, IdentityBundles aib
WHERE b.name LIKE 'DYP%' AND i.bundleSummary LIKE 'DYP%'
AND i.id = aib.identityId AND b.id = aib.bundle
I have the next error when I tried to run this query:
IdentityBundles is not mapped [select count(*) from sailpoint.object.Identity i, sailpoint.object.Bundle b, IdentityBundles aib
Looks like there is not mapping to IdentityBundles
The only think that I noticed in the jar files from the application is this list name ( founded in the Identity.hbm.xml file ) with the attributes from the table IdentityBundles
list name="bundles" table="IdentityBundles"
cascade="persist,merge,save-update">
key column="identityId"
list-index column="idx"
many-to-many column="bundle" class="sailpoint.object.Bundle"
list
Can I use this list to map the table or do I need to create the class and the hbm.xml file ??
Hibernate works with mappings. You are trying to specify the joins and since those are already mapped in your domain objects you don't need to do this. Use the domain object properties instead and Hibernate will fetch them for you.
from Identity i
join i.bundles b
where b.name like ...
etc.

Nested where clauses codeigniter mysql query

Is there any way to get nested where clauses? e.g.:
SELECT * FROM table WHERE (colA = 'valueA' AND colB = 'valueB') OR (colA = 'valueC' AND colB = 'valueD')
I know I could just write this into a query function call e.g.:
$this->db->query("SELECT ...")
But I was wondering if there was a "proper" way to do it in codeigniter e.g.:
$this->db->where(array('colA'=>'valueA'), array('colB'=>valueB'))->or_where(array('colA'=>'valueC'), array('colB'=>'valueD'))
thanks
With codeigniter 3, now there is, see the update!
There's no where() method usage variant with arrays that would allow you to do that. In these situations i usually just build the part in one long string like this:
$this->db->where("
(
(colA = '".$this->db->escape($v0)."' and colB = '".$this->db->escape($v1)."')
or
(colA = '".$this->db->escape($v2)."' and colB = '".$this->db->escape($v3)."')
)
");
Escaping can be done with escape(does some autodetection) or escape_str or escape_like_str manually depending on what the parameter expected to be or what the predicate in use.
If i'm on a project that uses the Datamapper library, i prefer to use the group_start() and group_end() methods when building these kind of queries, they have a lot of different flavor of these.
Update
Now with, Codeigniter 3 which have grouping methods in the query builder, so you can do ->group_start()s and ->group_end()s.
You can also try like
$this->db->where(condition1);
$this->db->or_where(condition2);

Resources