I am trying to check whether the room name in that building exists or not.If exists, then don't save else save the data into the table.So I have written this query.
#Query(value = "select exists(select name,building from meetingroom " +
"where building=?1 and name=?2)",nativeQuery = true)
Boolean existsByRoom(String building,String name);
Now it is showing BigInteger cannot be cast to class java.lang.Boolean
Is there any way to solve this without effecting or changing the query.
Simplest solution is here is to use JPA derived query.
Assuming your entity is MeetingRoom
Boolean existsMeetingRoomByBuildingAndName(String building, String name);
One solution is to use java.util.Optional like below. And you need to use BigInteger instead of Boolean because query will return BigInteger value when record exist.
#Query(value = "select exists(select name,building from meetingroom " +
"where building=?1 and name=?2)",nativeQuery = true)
Optional<BigInteger> existsByRoom(String building,String name);
And in service layer, you can check if the value is present.
Optional<BigInteger> result =
meetingRoomRepository.existsByRoom(meetingRoomRequest.getBuilding(),meetingRoomRequest.getName());
if(result.isPresent()){
return true;
}
return false;
Related
I want to implement Repository with delete query.
#Repository
public interface LogRepository extends JpaRepository<Log, Integer>, JpaSpecificationExecutor<Log> {
#Modifying
#Query("delete from " + Log.class.getName() + " r where r.createdAt <= ?1")
int deleteByCreatedAt(LocalDateTime createdAt);
}
But I get error The value for annotation attribute Query.value must be a constant expression
Is there some way to implement this?
The query "delete from " + Log.class.getName() + " r where r.createdAt <= ?1" is not constant indeed, as it will change with the change of the Log class. But why would you want to keep this dynamic? Is not like you will change the table name in the database very often. Just define it statically and you will be good to go.
Executing UPDATE query it always returns INT number of rows affected.
Maybe there is some way to return for example list of all objects which where updated or first one updated?
I have #Entity SecurityPolicy and want this object back after update.
So here is my code:
#Modifying
#Query(value = "UPDATE security_policy s set max_fail_sign_in =:maxFailSignIn," +
" min_password_length =:minPasswordLength," +
" capital_in_password =:capitalInPassword," +
" digit_in_password =:digitInPassword," +
nativeQuery = true)
SecurityPolicy updateSecurityPolicy(#Param("maxFailSignIn") Integer maxFailSignIn,
#Param("minPasswordLength") Integer minPasswordLength,
#Param("capitalInPassword") Boolean capitalInPassword,
#Param("digitInPassword") Boolean digitInPassword);
When using #Modifying it tells me that result should be Int, and without it - could not extract ResultSet.
I know with spring data you can easily save or update some entity and get it as a result, so I want achieve something similar.
No you cannot as the integer response is not generated by framework but by RDBMS itself (SQL spec). That integer says how many rows were modified by query.
Since you don't want to use JPA to do this, you will have to SELECT that row after update, like you would do with plain SQL.
I have a method in a JpaRepository that is supposed to be returning a List of JPA entities:
#Entity
public class SomeEntity {
// ...
}
#Repository
public interface SomeOtherEntityRepository extends JpaRepository<SomeOtherEntity, Long> {
#Query(value = "select some big long native query", nativeQuery = true)
public List<SomeEntity> getThings(String key);
}
When this query executes and I try to access the entries in the List, I get a ClassCastException:
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to my.package.SomeEntity
at java.util.ArrayList.forEach(ArrayList.java:1249)
at ...
When I debug, this is what I see:
This seems like it's breaking strongly typed variables in Java. I didn't know this was possible. I can change my code to expect an Object array and to convert the Object array to entities but this seems like something I shouldn't have to do.
JPA does not seem to support specifying a result class for #Query. You can use #NamedNativeQuery or EntityManager.createNativeQuery to specify a result class.
See http://www.thoughts-on-java.org/jpa-native-queries/
Your typed entity find method has to match the repository type. Here, you are declaring your repository entity to be SomeOtherEntity, but your find method getThings is returning (a list of) SomeEntity.
You need to use SqlResultSetMapping. A good tutorial is: http://www.thoughts-on-java.org/result-set-mapping-basics/
Example code:
Query q = em.createNativeQuery(
"SELECT o.id AS order_id, " +
"o.quantity AS order_quantity, " +
"o.item AS order_item, " +
"i.name AS item_name, " +
"FROM Order o, Item i " +
"WHERE (order_quantity > 25) AND (order_item = i.id)",
"OrderResults");
#SqlResultSetMapping(name="OrderResults",
entities={
#EntityResult(entityClass=com.acme.Order.class, fields={
#FieldResult(name="id", column="order_id"),
#FieldResult(name="quantity", column="order_quantity"),
#FieldResult(name="item", column="order_item")})},
columns={
#ColumnResult(name="item_name")}
)
I am connecting to a mysql db from standalone java application. My application uses several filters that determine, which data will be selected from db.
In some cases, I would like to construct the select command in a way, that its "WHERE" parameter is ignored and selects all values from db instead.
This is my example:
String query = "SELECT * from messages WHERE type='" + type + "' ORDER BY id DESC";
The variable type can contain some specific type that matches the Varchar of the items in my db. However, a user can set the type to "all values" (or something like that, I hope this is clear enough), in which case, the query would select ALL values from db (it will ignore the where parameter).
I know I could do this by simply putting some if statements in my code and call a different select command in every branch, but this would be highly ineffective in case that several specifications (attributes inside WHERE parameter) are used.
For example:
String query = "SELECT * from messages WHERE type='" + type + "' AND time='" + time + "' ORDER BY id DESC";
I am not sure whether this is even possible to do. If not, sorry about dumm question... Thanks in advance!
I think you will have to do it through code, nothing in SQL to do what you want to do. Typically, people use ORM like Hibernate and construct the query in more secure way (to avoid SQL injection) instead of using String concatenation.
This is how it is done in Hibernate: http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querycriteria.html#querycriteria-narrowing
You could create a Type class and a Time class and so on. This classes would contain a function called getSQL() which returns the type or in case of all types "".
The WHERE clause let you filter the dataset according to several predicates. Not specifying it means no filtering, hence all possible values for any predicates you would add.
If you consider the WHERE clause as a predicate, and predicates as either sets of predicates or atomic predicates, you can easily produce your clause by walking through the predicate nest and generate the needed string. If the string comes back empty, just elide the WHERE clause altogether.
interface Predicate {
public String toString();
}
// further derive this class for specific predicates
class AtomPredicate implements Predicate {
public AtomPredicate(){}
public toString() {}
}
// basic predicate set
class SetPredicate implements Predicate {
public SetPredicate(String connector){this.connector = connector;}
private ArrayList<Predicate> set;
private String connector;
public toString(){
String res, tmp;
int i;
if (set.size() == 0) return "";
while (res.size() == 0 && i < set.size()) {
res = set[i++].toString();
}
for (; i < set.size(); ++i) {
tmp = set[i].toString();
if (tmp.size() > 0)
res += connector + " " + tmp;
}
if (res.size() > 0)
return "(" + res + ")";
}
class WhereClause {
public WhereClause() {}
private Predicate predicate;
public toString(){
String res = predicate.toString();
if (res.size() > 0) return "WHERE " + res;
return "";
}
}
You can start from that basic outline, and expand as needed. You should however try to look for an existing solution first, like the jboss library linked in another answer, to avoid reinventing the wheel.
If I have a method to create SQL queries, as below :
public List selectTuple() {
boolean status = true;
String query = "SELECT ";
query += getFields() == null ? " * " : " " + getFields() + " ";
query += " FROM " + tables;
if ( getSearchClause() != null ) {
query += " " + getSearchClause();
}
query += ";";
Debug("SQL...........caleed selectTuple method, query is : "+ query);
setQuery(query);
if ( getPrepared() ) {//If this is a Prepared query,
status = setPreparedStatement();
} else {
status = setNonPreparedStatement();
}
if ( ! status ) {
Log("[CRITICAL] (.........)..........");
}
status = doExecuteQuery();
if ( ! status ) {
Log("[CRITICAL] (.........)..........");
}
return( getResults() );
}//method selectTuple
However, since this will be used for different tables, the fields will be of different data types (int, string, date etc). So how can I iterate through such a ResultSet ?
Also, how can I create such an Insert query ?
Thanks.
Yes, I think it could be done... You can use getMetaData() in the ResultSet to get the number and type of columns and iterate through the ResultSet consequently.
getMetaData():
ResultSetMetaData class
However, I don't know how to code such a generic insert query...
You will need to use getObject and pass a map of JDBC to Java object mappings for your own types if any.
So, if your table has column i numeric and column s varchar the next code
ResultSet rs = st.executeQuery("select i, s from test");
rs.next();
System.out.println(rs.getObject(1).getClass());
System.out.println(rs.getObject(2).getClass());
will result in
class java.lang.Integer
class java.lang.String
the only thing for you to do is to check the returned Object for its class, using instanceof, to do the actual casting.
You can refer to this article for more details.
For the insert part you could use setObject method and rely on JDBC conversion, which is probably not a very good idea but should work.
As #jahroy commented, avoid using JDBC for this type of generic things. I also just had the same problem and I came up with an easy and elegant way to do it with JPA
Here's a generic method I've created to handle any SELECT query, you can get the idea how JPA works. In this case I just wanted to make sure there were only SELECT queries but you can make it more generic, to accept INSERT, DELETE, UPDATE...
public List executeSelectQuery(String selectQuery, Class entityClass, String classPersistentUnit)
{
selectQuery = selectQuery.toUpperCase();
if(!selectQuery.startsWith("SELECT"))
{
throw new IllegalArgumentException("This method only accepts SELECT queries. You tried: " + selectQuery);
}
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(classPersistentUnit);
EntityManager entityManager = entityManagerFactory.createEntityManager();
Query query = entityManager.createNativeQuery(selectQuery, entityClass);
return query.getResultList();
}
The good thing is that Netbeans and Eclipse (and probably more IDEs too, but I just use these two) come up with an "auto-create" class Entity, on the fly! You don't need to code anything at all on these entity classes. An entity class, briefly, represents a table in your database. Therefore each table in your database will be represented by an entity class.
You can find an easy and small tutorial here