javax.persistence.NoResultException: No entity found for query - java

Before I posted this question, I already looked this, but I couldn't get what I was looking for.
I know that for the query I wrote there may exist only one row or none at all. So, there is not reason for me to use getResultList().
Here is my code:
String hql="from DrawUnusedBalance where unusedBalanceDate= :today";
Query query=em.createQuery(hql);
query.setParameter("today",new LocalDate());
DrawUnusedBalance drawUnusedBalance=
(DrawUnusedBalance)query.getSingleResult();// we can have only a
// single datum per day
//`System.out.println(drawUnusedBalance.toString());`
The problem is, if there is no row, it throws an exception, and if not it works fine. I know the problem but I am also looking for the best solution.
What I wanted is, if there is no row in the DB I wanted to get a null object (instead of getting an exception) so I will insert a new data, if it is not null, I just want to update it.
There is one way to handle this, which I believe is not the right way to do it. It is: I will have a try-catch block and if it throws an exception I can write to insert new data in to the DB on the catch block. But I believe there will be a better way.

Yes. You need to use the try/catch block, but no need to catch the Exception. As per the API it will throw NoResultException if there is no result, and its up to you how you want to handle it.
DrawUnusedBalance drawUnusedBalance = null;
try{
drawUnusedBalance = (DrawUnusedBalance)query.getSingleResult()
catch (NoResultException nre){
//Ignore this because as per your logic this is ok!
}
if(drawUnusedBalance == null){
//Do your logic..
}

When using java 8, you may take advantage of stream API and simplify code to
return (YourEntityClass) entityManager.createQuery()
....
.getResultList()
.stream().findFirst();
That will give you java.util.Optional
If you prefer null instead, all you need is
...
.getResultList()
.stream().findFirst().orElse(null);

You mentioned getting the result list from the Query, since you don't know that there is a UniqueResult (hence the exception) you could use list and check the size?
if (query.list().size() == 1)
Since you're not doing a get() to get your unique object a query will be executed whether you call uniqueResult or list.

Another option is to use uniqueResultOptional() method, which gives you Optional in result:
String hql="from DrawUnusedBalance where unusedBalanceDate= :today";
Query query=em.createQuery(hql);
query.setParameter("today",new LocalDate());
Optional<DrawUnusedBalance> drawUnusedBalance=query.uniqueResultOptional();

When you don't know whether there are any results, use getResultList().
List<User> foundUsers = (List<User>) query.getResultList();
if (foundUsers == null || foundUsers.isEmpty()) {
return false;
}
User foundUser = foundUsers.get(0);

String hql="from DrawUnusedBalance where unusedBalanceDate= :today";
DrawUnusedBalance drawUnusedBalance = em.unwrap(Session.class)
.createQuery(hql, DrawUnusedBalance.class)
.setParameter("today",new LocalDate())
.uniqueResultOptional()
.orElseThrow(NotFoundException::new);

Related

When I use insert, update(DML statements) in mybatis, how can I be sure that they are executed successfully?

I have seen two common ways
one checks return like this
int returnCount = userMapper.insert(user);
if (returnCount == 0) {
return "insert fails";
}
another way checks if function throws exception
try {
userMapper.insert(user);
} catch (Exception e) {
return "insert fails";
}
Actually, it also confused me when I study PrepareStatement executeUpdate method in JDBC.
In my view, if a method like that executed successfully, it returns a int value(no matter if it equals zero),or it will throw exception, but I'm not sure for that.
Thanks for the comment above, I just figured it out.I read some other blogs and thought about the comment carefully.Actually, success is a very subjective concept. A statement may execute normally(which means no exception thrown), it also can be unsuccess if the result does not meet our expectation(like updating a record that we thought existed but did not actually exist).That's why we check returns.

Handle Nullpointerexception after SQL query has no result

I've got a MVC based Java application with three models: Room, Student and StudentRoom.
StudentRoom contains an object of Room and Student.
Now I've got the problem that if my SQL query returns no result and I check the value of student's name like this
if(studentRoom.student.name != null) {
}
I'll get a NullPointerException and I don't know how to handle it.
Should I set Student.name = ""; since my query has no result?
if(studentRoom != null && studentRoom.student != null && studentRoom.student.name != null){
//.. Access student
}
Above solution looks a bit weird. you should better use getter/setter methods instead of directly accessing the objects.
Apart from that you can define methods like isStudentAvailable() in studentRoom to check whether it has Student in it or not.
Should I set Student.name = ""; since my query has no result ?
It completely depends on your use case. But I must say better to keep it null as it will raise the exception instead of passing the null check validations.
You might need a try/catch statement for that. Something like this :
try {
// do process here
} catch (NullPointerException npe) {
//to do if student is null
}
But take note, if there are any object that is inside the try statement, a NullPointerException would still be thrown. Hope this helps.

Java SQL: Statement.hasResultSet()?

My app uses MySQL on one platform and SQLite on another, as such there are differences, such as that when using query like DELETE FROM USERS:
On MySQL, PreparedStatement.getResultSet() will return null.
On SQLite, PreparedStatement.getResultSet() will throw java.sql.SQLException: no ResultSet available.
This may or may not be a bug in SQLite implementation (I think it is supposed to return null), but I have to deal with this somehow.
I could use a try { ... } catch (SQLException e) { ... } and if the exception message is "no ResultSet available", simply return null manually. This doesn't feel like a right way to do it though.
I could put up an if that makes a check on what JDBC driver is being used and react accordingly, but again, that doesn't feel like a good solution to the problem.
What I would really like is either a method like .hasResultSet() that returns a boolean OR a way to get the SQL command (SELECT, UPDATE, INSERT etc) from a statement that has been executed. I can find neither of the two in SQL API though.
When executing a query that returns an unknown amount of results, then you need to use execute(). This method returns a boolean indicating the type of result:
true: result is a ResultSet
false : result is an update count
If the result is true, then you use getResultSet() to retrieve the ResultSet, otherwise getUpdateCount() to retrieve the update count. If the update count is -1 it means there are no more results. Note that the update count will also be -1 when the current result is a ResultSet. It is also good to know that getResultSet() should return null if there are no more results or if the result is an update count, so the behavior of SQL Lite to throw an exception seems to be wrong.
Now if you want to retrieve more results, you call getMoreResults() (or its brother accepting an int parameter). The boolean return value of this method has the same meaning as that of execute(), so false does not mean there are no more results!
There are only no more results if the getMoreResults() returns false and getUpdateCount() returns -1 (as also documented in the Javadoc)
Essentially this means that if you want to correctly process all results you need to do something like:
PreparedStatement pstmt = connection.prepareStatement(...);
// ...
boolean result = pstmt.execute();
while(true)
if (result) {
ResultSet rs = pstmt.getResultSet();
// Do something with resultset ...
} else {
int updateCount = pstmt.getUpdateCount();
if (updateCount == -1) {
// no more results
break;
}
// Do something with update count ...
}
result = pstmt.getMoreResults();
}
The problem is that you use invalid method to perform delete operation. Instead of using getResultSet you should use Statement#execute(String)
IMHO the Exeption in SQLite implementation is more valid than null for MySQL. As delete do not return the set but a scalar value of delted rows.

Hibernate restriction in causes an error if the list is empty

If my list is empty, I get the following error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')'
Below is my hibernate related method:
#Override
public List<SomeThing> findByIds(List<Integer> someIds) {
return sessionFactory.getCurrentSession().createCriteria(SomeClass.class)
.add(Restrictions.in("id", someIds))
.list();
}
What should I do to guard against this error?
I know I could short-circuit the call and return an empty list like:
if(someIds == null || someIds.size() == 0) {
return new List<SomeThing>();
}
But is there a more elegant way to do this?
I would say Hibernate needs to fix this issue, and give meaningful message.
I think its responsibility of the provider/hibernate to check for the empty/null List.
One can imagine the cause, it tries to construct where clause, something like id in (), somewhere in org.hibernate.loader.criteria.CriteriaQueryTranslator or similar..But because here the List is empty, it would be throwing an exception. But they already created query with ( and could not complete because of exception/empty List.
NO. If you execute the query with empty parameters for in clause, it will fail (you may verify this by running plain SQL). Better not to execute the query if the input param is null/empty.
Only thing I can advice is to use isEmpty() function and != null in if statement and little restructuring as:
#Override
public List<SomeThing> findByIds(List<Integer> someIds) {
List<Something> result = null; //you may initialize with empty list
if(someIds != null || !someIds.isEmpty() {
result = sessionFactory.getCurrentSession().createCriteria(SomeClass.class)
.add(Restrictions.in("id", someIds))
.list();
}
return result;
}
(This is mostly base on #Yogendra Singh's reply, with a twist to make it more adoptable to commonly-seen situation of multiple optional argument)
Criteria API aims to let you compose your query programmatically. Such kind of dynamic feature is expected to be handled in your code.
Normally we make optional criteria by this:
#Override
public List<SomeThing> findBySearchParams(SearchParam searchParam) {
// create criteria with mandatory search criteria
Criteria criteria = sessionFactory.getCurrentSession()
.createCriteria(SomeClass.class);
.add(Restriction("someField", searchParam.getSomeField()));
// add "id" only if "someId" contains value
if(searchParam.getSomeIds() != null && !searchParam.getSomeIds().empty()) {
criteria.add(Restrictions.in("id", searchParam.getSomeIds()));
}
// add "anotherField" only if "anOptionalField" is not null
if(searchParam.getAnOptionalField() != null) {
criteria.add(Restrictions.in("anotherField", searchParam.getAnOptionalField()));
}
return criteria.list();
}
Edit:
Although Hibernate does not (yet) provide a more elegant way for that, you can write something yourself to make it looks more elegant:
class SmartCriteriaBuilder {
private Criteria criteria;
SmartCriteriaBuilder (Criteria criteria) { this.criteria = criteria;}
SmartCriteriaBuilder in(String field, Collection values) {
if (!empty(values)) {
this.criteria.add(Restrictions.in(field,values));
}
}
// all other kind of restrictions ....
Criteria toCriteria() {
return this.criteria;
}
}
Then you can do something looks smarter:
SmartCriteriaBuilder criteriaBuilder =
new SmartCriteriaBuilder(sessionFactory.getCurrentSession().createCriteria());
criteriaBuilder .in("someField", listPossiblyNullOrEmpty);
return criteriaBuilder .toCriteria().list();

Correct way to return a single result where multiple results may exist

In the following code, the ssNo parameter should ensure that only a single Employee satisfies the query condition:
Employee employee = null;
List<Employee> results = (List<Employee>) query.execute(ssNo);
if (results.iterator().hasNext())
{
for (Employee r : results)
{
employee = r;
}
}
return employee;
But if there are multiple results, the for loop ensures that the last Employee in the loop will be returned:
for (Employee r : results)
{
employee = r;
}
Is there a cleaner way to perform this kind of check?
Following the mantra that "less code is good", this code is equivalent to your code, but expressed in much less code and more clearly.
List<Employee> results = (List<Employee>) query.execute(ssNo);
return results.isEmpty() ? null : results.get(results.size() - 1);
It's more common to see the first element returned:
return results.isEmpty() ? null : results.get(0);
Another common pattern is:
if (results.size() > 1)
throw new IllegalStateException("Multiple results found, but at most one was expected");
Note that you can over-abbreviate your code to the point of "encryption", but as long as the code is still clear, less code is always better than more code.
Choosing the last employee is not a good idea, because if you expect to get only one employee, but instead, you get several ones, then you are likely to have a bug in your application or some data integrity problem that will go unnoticed, because you just return an arbitrary one. I'd throw an exception instead.
A clean API would look something like this:
// This returns a list of employees matching your search criteria
// Typical criteria are names, age, salary ranges, etc
// It will never be null, but maybe an empty list
List<Employee> getEmployeesByCriteria(... criteria);
// This will return at most one employee, depending on your search criteria
// Typically, you'll use an ID as criteria. If you don't find the employee
// you can either return null, or throw an exception. If you find several
// employees, then you should always throw an exception.
Employee getEmployeeByCriteria(... criteria) throws SomeException;
A minor simplification could be to remove the if check since the loop will get the last result anyway if the results are more than one.
If the result is only one that the first one is the last one so the if check is not needed.
I have to agree with Lukas Eder. If you're using a database, you should make sure the ssNo field is unique. If you are working only in memory, you should use a Hashtable using the ssNo as a key, and that would throw an exception when you try to insert on a key already used.
In any case, this part of your code is not the place (or this should not be) to check the validity of your datas.
If the query return more the one expected results you should throw an exception that this is not correct.
But if you are 100% sure that this is good way for your case then this look better.
List<Employee> results = (List<Employee>) query.execute(ssNo);
if(results.size() > 0) {
return results.get(results.size() - 1);
}

Categories