Spring Data JPA #Query with foreign key: Parameter not matched - java

I have a table "Signal" with id, volume and object_id columns.
Object_id is a foreign key. I need to retrieve each signal that has a particular object_id.
Im trying to use this Query
public interface SignalRepository extends JpaRepository<Signal, Integer> {
#Query("select s from Signal s where s.object = ?1")
Optional<List<Signal>> findSignalByObjectId(Integer objectId);
}
It doens't work. If I change "?1" to 1 it gets the hardcoded value. If I try to query the "volume", it works fine.
I get this error:
Blockquote
nested exception is java.lang.IllegalArgumentException: Parameter value [1] did not match expected type

I'd recommend you omit the query and let spring data generate one for you. So your case may be represented somehow like that (in case of proper relation mapping defined):
public interface SignalRepository extends JpaRepository<Signal, Integer> {
Optional<Signal> findByObject(YourObjectType object);
}
If you provide more info e.g. your entities - you can get more help.

You can use Spring data to generate the underlying query like this :
public interface SignalRepository extends JpaRepository<Signal, Integer> {
List<Signal> findSignalByObjectId(Integer objectId);
}
or you can write the query with this return type and parameter:
public interface SignalRepository extends JpaRepository<Signal, Integer> {
#Query("select s from Signal s where s.object = :id")
List<Signal> findSignalByObjectId(#Param("id") Integer objectId);
}

Related

Android Room #Delete with parameters

I know I can't use DELETE in a query (that is a shame by the way), I will get the following error:
<i>Error:error: Observable query return type (LiveData, Flowable etc) can only be used with SELECT queries that directly or indirectly (via #Relation, for example) access at least one table.</i>
But I can't use #Delete(WHERE... xxx)
So how do I delete a specific row by a parameter?
Actually, you can use #Query to perform a delete.
#Query("DELETE FROM users WHERE user_id = :userId")
abstract void deleteByUserId(long userId);
Extracted from Query javadoc:
UPDATE or DELETE queries can return void or int. If it is an int, the
value is the number of rows affected by this query.
The beauty of room is, we play with the objects. As per requirement you can use
for kotlin:
#Delete
fun delete(model: LanguageModel)
for Java:
#Delete
void delete(LanguageModel model)
it will delete the exact object which is stored in the db with the same values. LanguageModel is my model class and it works perfectly.
You can use below method to delete by ID
#Query("DELETE FROM yourDatabaseTable WHERE id = :id")
void deleteById(int id);
for delete all rows
#Query("DELETE FROM yourDatabaseTable")
void delete();
ROOM database provides easy way to INSERT, UPDATE and DELETE an object in the database. To perform thus operation just needed to annotate #Delete. The DELETE operation returns the Int when deletion of the single object is successful returns 1 else returns 0 if the DELETE operation is unsuccessful, Adding the return type is a good practice.
KotlinEG.kt
#Dao
interface EntityLocalDAO {
#Delete
fun deleteData(entityObject: EntityObject) : Int
}
javaEG.java
#Dao
interface EntityLocalDAO {
#Delete
int deleteData(EntityObject entityObject);
}
You can now delete using only partial data.
Per the documentation:
#Entity
data class Playlist (
#PrimaryKey
val playlistId: Long,
val ownerId: Long,
val name: String,
#ColumnInfo(defaultValue = "normal")
val category: String
)
data class OwnerIdAndCategory (
val ownerId: Long,
val category: String
)
#Dao
public interface PlaylistDao {
#Delete(entity = Playlist::class)
fun deleteByOwnerIdAndCategory(varargs idCategory: OwnerIdAndCategory)
}
In this example you can see that they are deleting the Playlist using only the ownerId and the category. You do not even need to use the primary key (playlistId).
The key is to use the #Delete(entity = Playlist::class) annotation.

Spring jdbcTemplate passing constant value to an query method

Is it possible to mention an values as constant in the function. I have an entity say, EntityClass. Then a repository interface over it, say
interface EntityClassRepository extends CrudRepository<EntityClass, String> {
List<EntityClass> findById(String id);
}
Can I hard code some value in the method like,
List<EntityClass> findByIdAndActiveFlagAsY(String id);
To only query the ones where active flag column's value is 'Y'.
Is it possible?
No, spring data not support AS keywords inside method names, you can check all the Supported keywords inside method names :
So to solve your problem you can use custom query instead :
#Query("from EntityClass e WHERE id = :id AND ActiveFlag = 'Y'")
public List<EntityClass> findByIdAndActiveFlagAsY(#Param("id") String id);
Or you can use Equals keywords but you should to send the value in the method :
#Query("from EntityClass e WHERE id = :id AND ActiveFlag = :flag")
public List<EntityClass> findByIdAndActiveFlagEquals(#Param("id") String id, #Param("flag") String flag);

Spring Data JPA and Exists query

I'm using Spring Data JPA (with Hibernate as my JPA provider) and want to define an exists method with a HQL query attached:
public interface MyEntityRepository extends CrudRepository<MyEntity, String> {
#Query("select count(e) from MyEntity e where ...")
public boolean existsIfBlaBla(#Param("id") String id);
}
When I run this query, I get a java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Boolean.
How does the HQL query have to look like to make this work? I know I could simply return a Long value and afterwards check in my Java code if count > 0, but that workaround shouldn't be necessary, right?
Spring Data JPA 1.11 now supports the exists projection in repository query derivation.
See documentation here.
In your case the following will work:
public interface MyEntityRepository extends CrudRepository<MyEntity, String> {
boolean existsByFoo(String foo);
}
I think you can simply change the query to return boolean as
#Query("select count(e)>0 from MyEntity e where ...")
PS:
If you are checking exists based on Primary key value CrudRepository already have exists(id) method.
in my case it didn't work like following
#Query("select count(e)>0 from MyEntity e where ...")
You can return it as boolean value with following
#Query(value = "SELECT CASE WHEN count(pl)> 0 THEN true ELSE false END FROM PostboxLabel pl ...")
It's gotten a lot easier these days!
#Repository
public interface PageRepository extends JpaRepository<Page, UUID> {
Boolean existsByName(String name); //Checks if there are any records by name
Boolean existsBy(); // Checks if there are any records whatsoever
}
Since Spring data 1.12 you can use the query by Example functionnality by extending the QueryByExampleExecutor interface (The JpaRepositoryalready extends it).
Then you can use this query (among others) :
<S extends T> boolean exists(Example<S> example);
Consider an entity MyEntity which as a property name, you want to know if an entity with that name exists, ignoring case, then the call to this method can look like this :
//The ExampleMatcher is immutable and can be static I think
ExampleMatcher NAME_MATCHER = ExampleMatcher.matching()
.withMatcher("name", GenericPropertyMatchers.ignoreCase());
Example<MyEntity> example = Example.<MyEntity>of(new MyEntity("example name"), NAME_MATCHER);
boolean exists = myEntityRepository.exists(example);
Apart from the accepted answer, I'm suggesting another alternative.
Use QueryDSL, create a predicate and use the exists() method that accepts a predicate and returns Boolean.
One advantage with QueryDSL is you can use the predicate for complicated where clauses.
You can use Case expression for returning a boolean in your select query like below.
#Query("SELECT CASE WHEN count(e) > 0 THEN true ELSE false END FROM MyEntity e where e.my_column = ?1")
Spring data provides method for checking the existence of a row using field:
example: boolean existsByEmployeeIdAndEmployeeName(String employeeId, String employeeName);
You can use .exists (return boolean) in jpaRepository.
if(commercialRuleMsisdnRepo.exists(commercialRuleMsisdn.getRuleId())!=true){
jsRespon.setStatusDescription("SUCCESS ADD TO DB");
}else{
jsRespon.setStatusCode("ID already exists is database");
}

Spring data JPA query behaves unexpectedly

I have these entities:
public class Order_status_sas {
private Order_sas order;
private Date lastModified;
...
}
public class Order_sas {
private long id;
...
}
My CrudRepository:
public interface StatusesWareHouseRepository extends CrudRepository<Order_status_sas, Long> {
Order_status_sas findFirstByOrderIdOrderByLastModifiedDesc(long id);
}
I expect that method findFirstByOrderIdOrderByLastModifiedDesc would return first row from table Order_status_sas, where order.id = <some_id> sorted by field lastModified, but in log I see this query:
Hibernate: select ...
from order_status_sas a
left outer join orders_sas b
on a.order_id=b.id
where b.id=?
order by a.last_modified desc
This query does not return me one row, but returns a list of rows. It seems that Spring Data do not look at word First in my method name. Also, I get an Exception:
org.springframework.dao.IncorrectResultSizeDataAccessException:
result returns more than one elements; nested exception is javax.persistence.NonUniqueResultException: result returns more than one elements
Please, tell me what I am doing wrong and how can I achieve my purpose?
EDITED:
I edited my StatusesWareHouseRepository with custom query:
#Query("select s from Order_status_sas s where s.order.id = ?1 order by s.lastModified desc limit 1")
Order_status_sas findFirstByOrderIdOrderByLastModifiedDesc(long id);
but the query, executed by Hibernate, haven't changed. It looks like this:
select ...
from order_status_sas s
where s.order_id=?
order by s.last_modified desc
OK, I understood #PriduNeemre point. Lets leave the DB model and come back to the JPA question. Here is another example:
#Entity
public class Client {
....
}
public interface ClientRepository extends CrudRepository<Client, Integer> {
Client findFirstByOrderByNameDesc();
}
Hibernate query still looks like this:
select ...
from clients c
order by c.name desc
Have you tried adding a #Query annotation (see here) on top of your findFirstByOrderIdOrderByLastModifiedDesc(..) method to specify the expected behaviour by hand? A (non-related) example on how this could work:
public interface InvoiceRepository extends JpaRepository<Invoice, Long> {
#Query("SELECT I FROM Invoice I JOIN I.customer C JOIN C.user U WHERE
U.username = :username")
public List<Invoice> findInvoicesByUsername(#Param("username")
String username);
}
Note that the query language used in the annotation body is in fact JPQL, not SQL. For more examples on the #Query annotation, see the Spring Data docs here.
PS: I'm also having conflicted feelings about your domain object structure, i.e. whether an instance of Order_sas should really be stored in an instance of Order_status_sas - shouldn't it be the other way around? Normally you would want to store the reference objects in your main domain object, not vice versa. (There's a slight possibility that I'm just not getting it right, though.)
EDIT: I would even go as far as to say that considering your current domain model, Hibernate is doing everything right except missing a LIMIT 1 clause to limit the expected resultset to one single row. The query itself is extremely inefficient, though, and could be improved by fixing your skewed domain model.

Selecting fields on Spring Data

I'm trying to find information about how to select only certain fields of an entity using Spring Data (I'm using JPA). I want to select only specific information of an entity, the repository interfaces gives you the ways to return the information of the WHOLE entity!. Some times I only need 2 or 3 fields of an entity and returning 20,30, ...100.. fields may be a little overkill.
This kind of functionality is something that I would do using Hibernate Criteria Projections, or even JPA "SELECT NEW ...." queries. Don't know if it is possible with Spring Data.
Thanks.
What you can do is return a List<Object[]> from repository. Then in your service class iterate over this list and manually create the object you need. Sample repository method
#Query("select el.moduleId, el.threadId from ExceptionLog el")
public List<Object[]> tempQuery();
I think you can also do it in this way
SomeDataPOJO{
required col1
required col2
}
and then write query like this
#Query("select new SomeDataPOJO from requiredTable where xyz="abc")
public List<SomeDataPoJO> tempQuery()
Its not plain Spring Data but did you consider using Springs JdbcTemplate? Its also in the Context if you use Spring Boots Autoconfiguration and has several handlers for transforming results of the Query.
For Example for the Query SELECT a, b FROM EMPLOYEE WHERE ID = ? you could use
String query = "SELECT a, b FROM EMPLOYEE WHERE ID = ?";
List<Pair<String,Integer>> employees = jdbcTemplate.queryForObject(
query, new Object[] { id }, new ExampleRowMapper());
Where the ExampleRowMapper transforms each row from the result into your given Return type (Pair<String, Integer> in this case) and could look like
public class ExampleRowMapper implements RowMapper<Pair<String, Integer>> {
#Override
public Pair<String, Integer> mapRow(ResultSet rs, int rowNum) throws SQLException {
return Pair.of(rs.getString(1), rs.getString(2));
}
}
Example adapted from https://www.baeldung.com/spring-jdbc-jdbctemplate where you find more information.
Of course its not as typesafe as a JPQL as the Query is "raw" or "native" SQL but at least the response is again typesafe and I like it more than to return Object[] or something.

Categories

Resources