Can I pass an attribute as parameter in a method from my Repository?
Example:
#Query("select a from Account a where :attr = :value")
public Page<Account> searchByFilter(#Param("attr")
String attribute,#Param("value")String value,Pageable pageable);
Call example :
searchByFilter("status","Active",....);
Thanks
No, it is not possible.
Basically your query can be compiled and successfully executed, however it will be translated not the way you like.
At the end you'll have sql like this
select a.* from account a where 'status' = 'Active';
Note: status is translated to string value, not the column name.
Related
Currently I use the following code for a custom SQL statement in a Spring Data JDBC Repository interface:
default void upsert(LoanRecord r) {
upsert(r.getId(), r.getUcdpDocumentFileId(), r.getFreSellerNo(),
r.getFreDeliverySellerNo(), r.getLenderLoanNo(), r.getFreLpKey());
}
#Modifying
#Query("""
INSERT INTO loan (id, ucdp_document_file_id, lender_loan_no, fre_seller_no, fre_delivery_seller_no, fre_lp_key)
values (:id, :ucdpDocumentFileId, :lenderLoanNo, :freSellerNo, :freDeliverySellerNo, :freLpKey)
ON CONFLICT (ucdp_document_file_id) DO UPDATE SET
lender_loan_no = EXCLUDED.lender_loan_no,
fre_seller_no = EXCLUDED.fre_seller_no,
fre_delivery_seller_no = EXCLUDED.fre_delivery_seller_no,
fre_lp_key = EXCLUDED.fre_lp_key""")
void upsert(UUID id, String ucdpDocumentFileId, String freSellerNo,
String freDeliverySellerNo, String lenderLoanNo, String freLpKey);
The actual statement doesn't really matter, but as you can see, there's a wrapper method that unpacks the object so I can use simple parameters in the second method. Is there some way to refer to object properties in the query (like with MyBatis) so we can get rid of the wrapper method?
For reference, my spring-data-jdbc version is 2.4.2.
This is possible with the latest milestone release of Spring Data JDBC(3.0.0-RC1!
It is probably the main use case behind SpEL support.
With it you can now use constructs like this:
#Query("select u from User u where u.firstname = :#{#customer.firstname}")
List<User> findUsersByCustomersFirstname(#Param("customer") Customer customer);
Just as you can for a long time in Spring Data JPA.
I am trying to create an annotated insert statement using MyBatis where the type handler is specified in an annotation.
For example, in a select query we can specify the typehandler like this:
#Results({
#Result(column = "strings", property = "strings", typeHandler = StringArrayTypeHandler.class)
})
#Select("SELECT * FROM ${name} ORDER BY id ASC;")
List<StringObject> getStringObjects(#Param("name") String name);
However, the same does not appear possible for an insert query as the #Results annotation is only for #Select queries.
Currently, my work around is to specify the type handler as part of the query string like this:
#Options(useGeneratedKeys = true)
#Insert({"INSERT INTO ${name} (text, value, strings) VALUES (#{obj.text}, #{obj.value}, #{obj.strings, typeHandler=com.mypackage.typehandler.StringArrayTypeHandler});"})
void insertStringObject(#Param("obj") SenticConcept concept, #Param("name") String version);
My question is, can we specify the type handler class in an annotation rather than being part of the query string?
This can't be done.
The result mapping uses column names as keys because column values in the result set can be identified using column name, that is mybatis can get the value of some column by its name. So it can use a mapping configuration (for example typeHandler) to process the value in that column.
The input parameters to the query in JDBC are identifiable only by the index of the parameter. In principle it is possible to implement an annotation that would specify the typeHandler based on the index of the parameter, but this is error prone because a change in the query may cause the change in the parameter indices (that's probably the reason it is not done in mybatis).
Is a select query made by a java driver accessor vulnerable to injection?
Some like
#Query("SELECT * FROM table WHERE id = :id")
Result<Entity> byId(#Param("id") String id);
No, This syntax does not perform string replacement. It actually binds the value into a parameter slot. This means a malicious request would simply be treated as the id within a bound statement.
I need to set a table name dynamically so that I use query.setText(tname,abc)
e.g: select a.name from :tname where a.id = '2'
I used setText() because when I use setString() it says "tname is a invalid parameter" because I assume that Hibernate adds '' when setting string parameters.
But even setText() does not help and gives the same exception.
How can I set the table name dynamically?
Reply to PSR:
So you mean replace table name as a java string replacement. But then we can not take support of sql injections prevention etc from hibernate right? Also How we bind parameters in hibernate in a situation where like statement,
Eg: name like "%:name%"
This also gives me Illegal argument exception: Parameter does not exist as a named parameter when i try to bind it using query.setString(name,"def");
Hibernate will not do this for you, because it works with PreparedStatements, and you can't prepare a statement where the table being queried isn't known yet.
I don't see why you would be exposing table names to end users, so preventing SQL injection doing a regular string substitution should be easy. You use some sort of business logic to determine the correct table from a list that only you know. The table name isn't coming from user input at all.
Depending on your choice of RDBMS, you may find a discriminator column, or table inheritance with partitioning to be a better way of handling a situation where identical queries are made against different tables.
It is not possible to set table name dynamically.You can set dynamically column names.it is not possible to set table name
try like this
select a.name from '+table name+'where a.id = '2'
In my opinion, There are 2 ways to resolve this issue:
1- If you are using Spring and Hibernate together, you could use SpEL and it would be like #{#entityName} as it is described here
#Entity
public class User {
#Id
#GeneratedValue
Long id;
String lastname;
}
public interface UserRepository extends JpaRepository<User,Long> {
#Query("select u from #{#entityName} u where u.lastname = ?1")
List<User> findByLastname(String lastname);
}
2-You could use CriteriaBuilder like
CriteriaQuery<YourEntity> cr = cb.createQuery(YourEntity.class);
Root<YourEntity> root = cr.from(YourEntity.class);
cr.select(root);
I copied the source codes from the provided links and they are described there much better
I have an object in which a member is an enum, and I want to write a query returning all elements for which that member is in a list of values. So, I've written the following JQP query
#NamedQuery(name = MyBean.FIND_BY_STATUSES, query = "select t from "+MyBean.TABLE+" t where t.status member of :statuses"),
class MyBean {
#Enumerated(EnumType.STRING)
private MyEnum status;
}
That I try to get using the following EJB code
Query findByStatuses = getEntityManager().createNamedQuery(MyBean.FIND_BY_STATUSES);
findByStatuses.setParameter("statuses", Arrays.asList(statuses));
return findByStatuses.getResultList();
Unfortunatly, Glassfish endlessly tells me I'm wrong (which I am, obviously).
But what do I have to fix ? and how ?
First your query references to table name, so it tries to be kind of SQL, but maybe database does not have "MEMBER OF"-operator which would be suitable for this kind of use, so let's try with JPQL. There we cannot use MEMBER OF, because it takes path expression as an argument, and that is not what we provide in setParameter. Instead we use IN:
#NamedQuery(name = MyBean.FIND_BY_STATUSES, query = "select t from MyBean t where t.status in(:statuses)")
No need to modify part where you run query.