JAVA Spring Boot - existsByColumne1AndNotColumn2 Repository query - java

I am working with Java Spring Boot where I want to create default query to find if a user already exists with the given mobile number and not with the given user id. A raw query is this
SELECT * FROM `user` WHERE mobile = "9898989898" AND user_id != 123
I did found that to check with single column whether the data is exist in that column or not, we can do something like this in Repository class
Boolean ExistWithMobile(String mobile)
This will return true or false if row found with the given mobile number.
The same way I want query similar to above, but this is not working
Boolean existsByMobileAndNotUserId(String mobile, Long userId);
This should return true or false whether this phone number is available with Other userId
I know how can I work with raw queries, as I already mention that in starting of the question, but I want something like this direct way of query, without raw query.
Any help would be appreciated.

if you don't wanna use native sql query, you could use HQL instead.
in your case:
#Query("from User u Where u.mobile = :mob and u.id != :id")
Optional<User> findUserByMobile(#Param("mob") String mobile, #Param("id") long id)
when you call :
Optional<User> user = repo.findUserByMobile(mobile, uid);
if( user.isPresent() ) { ... }
here is doc of #Query in spring data :
Spring Data JPA
Good luck

Related

Handling dynamic queries with Spring

The problem I'm trying to solve here is, filtering the table using dynamic queries supplied by the user.
Entities needed to describe the problem:
Table: run_events
Columns: user_id, distance, time, speed, date, temperature, latitude, longitude
The problem statement is to get the run_events for a user, based on a filterQuery.
Query is of the format,
((date = '2018-06-01') AND ((distance < 20) OR (distance > 10))
And this query can combine multiple fields and multiple AND/OR operations.
One approach to solving this is using hibernate and concatenating the filterQuery with your query.
"select * from run_events where user_id=:userId and "+filterQuery;
This needs you to write the entire implementation and use sessions, i.e.
String q = select * from run_events where user_id=:userId and "+filterQuery;
Query query = getSession().createQuery(q);
query.setParameter("userId", userId);
List<Object[]> result = query.list();
List<RunEvent> runEvents = new ArrayList<>();
for(Object[] obj: result){
RunEvent datum = new RunEvent();
int index = -1;
datum.setId((long) obj[++index]);
datum.setDate((Timestamp) obj[++index]);
datum.setDistance((Long) obj[++index]);
datum.setTime((Long) obj[++index]);
datum.setSpeed((Double) obj[++index]);
datum.setLatitude((Double) obj[++index]);
datum.setLongitude((Double) obj[++index]);
datum.setTemperature((Double) obj[++index]);
runEvents.add(datum);
}
This just doesn't seem very elegant and I want to use the #Query annotation to do this i.e.
#Query(value = "select run_event from RunEvent where user_id = :userId and :query order by date asc")
List<RunEvent> getRunningData(#Param("userId") Long userId,
#Param("query") String query,
);
But this doesn't work because query as a parameter cannot be supplied that way in the query.
Is there a better, elegant approach to getting this done using JPA?
Using Specifications and Predicates seems very complicated for this sort of a query.
To answer the plain question: This is not possible with #Query.
It is also in at least 99% of the cases a bad design decision because constructing SQL queries by string concatenation using strings provided by a user (or any source not under tight control) opens you up for SQL injection attacks.
Instead you should encode the query in some kind of API (Criteria, Querydsl, Query By Example) and use that to create your query. There are plenty of questions and answers about this on SO so I won't repeat them here. See for example Dynamic spring data jpa repository query with arbitrary AND clauses
If you insist on using a SQL or JPQL snippet as input a custom implementation using String concatenation is the way to go.
This opens up attack for SQL injection. Maybe that’s why this feature is not possible.
It is generally a bad idea to construct query by appending random filters at the end and running them.
What if the queryString does something awkward like
Select * from Foo where ID=1234 or true;
thereby returning all the rows and bringing a heavy load on DB possibly ceasing your whole application?
Solution: You could use multiple Criteria for filtering it dynamically in JPA, but you’ll need to parse the queryString yourself and add the necessary criteria.
You can use kolobok and ignore fields with null values.
For example create one method like bellow
findByUserIdAndDistanceaLessThanAndDistancebGreaterThan....(String userid,...)
and call that method only with the filter parameters while other parameters are null

How do you return only x number of records back

I have an n API using Spring Boot to return the data back from my MySQL db.
I would like to send in a parameter (to keep it simple as part of the URI) to only return an x amount of records back.
My question is
Is it easier to just return all the records back in the Spring Boot app and then only loop through al the records and return the x amount of records back via an Arraylist or
Is there an actual method I can call with either JPA or the standard super class CRUD from Java to get the correct result?
You can use native query in your repository.
For example you have controller named fetch_data_controller and a repository name fetch_data_repository and a table name fetch_data_table from where you have to fetch only specific data.
In fetch_data_repository write the query as follows:
#Query(value = "SELECT col_1,col_2 FROM fetch_data_table WHERE validation = 1", nativeQuery = true)
List<Map<String,String>> fetch_data_func();
In fetch_data_controller write code as follows:
List<Map<String,String>> fetched_data = fetch_data_repository.fetch_data_func();

How do bulk update with EntityManager in JPA/Play based on certain conditions?

Currently, we're getting a ResultList of entities that fit a criteria and then looping through it and setting the same value on each of them one by one. This is very slow. How could we instead do a bulk update using EntityManager?
As an example, I want to set the field isValid to true for all users that have an SSN and Phone. How would I do this in an efficient/performant way?
Is it like this?
final int changes = entityManager.createQuery(
"update User set isValid = :isValid WHERE SSN IS NOT NULL AND Phone IS NOT NULL")
.setParameter("isValid", true)
.executeUpdate();

I can't use any ID in my code

I was always taught to use IDs in my code to refer to records into the database.
But let's take the case we have same roles in the table Role. Now I want to query only the records related to the role Player:
ID ROLE
1 Admin
2 Organizer
3 Player
I don't know in my code the ID of Player, but I want to retrieve all the players, so with Hibernate I wrote:
String queryString = "from User u where u.role.role = ?";
Query queryObject = getSession().createQuery(queryString);
queryObject.setParameter(0, "player");
return queryObject.list();
As you can see I wrote "player" in the code. I think this is not the best way and I should use an ID instead. But I don't know the ID and it may change depending on the server on which I run the application. A second problem with my solution is that "player" can be capitalized into the database and this may be changed over time.
So, what should be the solution to all these problems? Is there any way to use the ID instead? Or any other way to improve this code?
In this case it seems that role should be an enum and your query would look something like:
queryObject.setParameter(0, Role.PLAYER);
Also, you might take a look at the criteria API which will help you create more type-safe queries that are more robust vs. refactoring.
You should create a enum class like this.
public enum Role {
Admin(1),
Organizer(2),
Player(3);
}
And change your code to
String queryString = "from User u where u.id= ?";
Query queryObject = getSession().createQuery(queryString);
queryObject .setParameter(0, Role.PLAYER);
return queryObject.list();
You can do using create a mapping table like ,
UserRoleMapping
ID - Incremental,
UserId - Refers to user table,
RoleId - Refers to role table
As one user can have more than one role so it will satisfy that thing too.
to Get the roles using query
select role.id from userrolemapping urm innerjoin on user u.id = urm.id where u.id = ?
using IDs or string/vachar etc. lookup is all dependent on the data that you have in the database. Some organization keep the id static and some keep the name/description static. So, make sure you have good understanding of your DB data and what will stay static . However, if the role is static you can use HQL ignore case like the example I provided for you below (I'm not adding information about the ID static path because others have already provided information about it for and don't want to duplicate it ).
--note you can take the percentages out if you only want "player"
String queryString = "from User u where lower( u.role.role ) like lower('%"+ ? +"%')";
Query queryObject = getSession().createQuery(queryString);
queryObject.setParameter(0, "player");
return queryObject.list();

What's the fastest way to check if a row exists in DB using Hibernate & spring?

I need to check if a row exists in a database in a very fast way.
Let's say I've got the primary key.
I found this code snippet in Hibernate's FAQ website:
Integer count = (Integer) session.createQuery("select count(*) from ....").uniqueResult();
I just started using spring, so I have HibernateTemplate object injected into my class.
How do I translate this snippet to work with HibernateTemplate.
Does anyone knows a better/faster way than this ?
Thanks.
Long count = hibernateTemplate.execute(new HibernateCallback<Long>() {
#Override
public Long doInHibernate(Session session) {
return (Long) session.createQuery("select count(someEntity.id) from SomeEntiuty someEntity ...").uniqueResult();
}
});
Hibernate used Integer for count queries before, but now uses Long. Also, note that even if not deprecated, Spring recommends not to use HibernateTemplate anymore and use the Hibernate API directly (using sessionFactory.getCurrentSession()).
Fastest way of checking primary key exist or not in database.
public void exist(Long id) {
Session session = sessionFactory.getCurrentSession();
String queryString = "select 1 from Employee e where e.id= :id";
Query query = session.createQuery(queryString);
query.setParameter("id", 1l);
Integer result = (Integer) query.uniqueResult();
System.out.println(result);
}
Again this also depends on a lot on what engine that you are using MyISAM vs innodb.
select count(col1) from table; will return the number of rows where the column is not null.
select count(*) from table; will return the number of rows.
Depending upon the database that you are using , a select count(*) will be more expensive than reading it from meta data table or system level tables that keep track of the row count.
Just my 2 cents.
Depending upon various other factors like indexes and other information / joins / access privileges this may be faster
SELECT table_rows FROM `information_schema`.`TABLES` where table_schema = 'database_schema_name' and table_name = 'table_name';
I think it's better to get an specific representative field of the first row found (using the PK or at least another indexed field), than counting all of the possible records that would match your search criteria.
If you're using Spring it will throw EmptyResultDataAccessException if no record was found.

Categories