Testing whether a Lucene Query matches all the documents - java

Given an instance of Query is it possible to somehow check whether that instance happens to represent a query that always matches all the documents in the index?
For example, a MatchAllDocsQuery or a BooleanQuery that contains a MatchAllDocs clause are such queries that always return all the documents. Another example is a BooleanQuery that has a SHOULD-match clause that has a nested SHOULD-match clause that has a MatchAllDocs inside it.
Note that a query that happens to return everything because it has all the possible terms in it or because the index is empty doesn't count as a query that always return all the documents. In other words, I would like to check whether a given query always returns everything no matter what the index contains.
Is it possible or at least approximately possible? I'll accept an answer with a solution that doesn't work for any conceivable case if it works for any query that can be returned from Solr's Extended Dismax Query Parser.

A BooleanQuery that contains a MatchAllDocsQuery as one of it's clauses doesn't necessarily return all documents, as the BooleanQuery may also contain other MUST or MUST_NOT clauses which would restrict the result set. I don't believe there is anything the does this out of the box, and trying to handle any sort of query that Solr might split out would be difficult. You would need to move through the queries recursively to ensure that everything effectively reduces to a MatchAllDocsQuery, ignoring scores.
Something like (this is entirely untested at this point):
boolean willMatchAll(Query query) {
if (query instanceof MatchAllDocsQuery)
return true;
}
else if (query instanceof BooleanQuery) {
boolean foundMatchAll = false;
for (BooleanClause clause : ((BooleanQuery)query).getClauses()) {
if (clause.isProhibited()) {
return false; //A reasonable assumption, that the MUST_NOT clauses won't be empty
}
else if (clause.isRequired()) {
if (willMatchAll(clause.getQuery())) {
foundMatchAll = true;
} else {
return false; //any MUST clause that is not a matchall means the boolean query will not match all
}
}
else {
if (willMatchAll(clause.getQuery())) {
foundMatchAll = true;
}
}
}
//If a matchall has been found, and we haven't return false yet, this boolean query matches all documents
return foundMatchAll;
}
else if (query instanceof DisjunctionMaxQuery) {
boolean isMatchAll = false
//If any disjunct is a matchall, the query will match all documents
for (Query subquery : ((DisjunctuionMaxQuery)query).getDisjuncts()) {
isMatchAll = isMatchAll || willMatchAll(subquery);
}
return isMatchAll;
}
else if (query instanceof ConstantScoreQuery) {
//Traverse right through ConstantScoreQuery. The wrapper isn't of interest here.
Query subquery = ((ConstantScoreQuery)query).getQuery()
if (subquery == null) {
return false; //It wraps a filter, not a query, and I don't believe a filter can be a matchall
}
return willMatchAll(subquery);
}
else {
//No other standard queries may be or contain MatchAllDocsQueries, I don't believe.
//Even a double open-ended range query restricts the results to those with a value in the specified field.
return false;
}
}
And if you also wanted to handle the stuff in org.apache.lucene.queries, there would be more query types to handle, like BoostingQuery and CustomScoreQuery, among others. But hopefully that gives some sort of idea on it.

Good question, i am wondering if you can do : search and get numFound and compare that to see if your actual Query returns same numFound value. Am i missing something?

Related

Querying on Java Object's without Database

Note: Little long question. I'm going to give a bounty for best answer.
What I'm trying to do is querying on Object. Here is the details. I have a file called employee.txt. So I parsed it and kept in the list
public static List<Employee> employeeList = new LinkedList<>();
Then here is my logic to query.
Take the query from user, and then parse it. The below is the logic to query through the list.
For ex: here is the query
select * from Employee where id > 10
My codes for that
String valueToCompare = split[5]; //10
EmployeeCriteria criteria = new EmployeeCriteria(
isId, isName, isSalary, expression,
valueToCompare);
result = EmployeeData.findAll(
EmployeeData.employeeList, criteria);
Here is the findAll method
public static List<Employee> findAll(List<Employee> coll,
ISearch<Employee> chk) {
List<Employee> l = new LinkedList<Employee>();
for (Employee obj : coll) {
if (chk.search(new Employee(obj)))
l.add(obj);
}
return l;
}
And here is my search method
/**
* Based on the type provided and for given expression it check against the
* given value
*/
#Override
public boolean search(Employee obj) {
if (expression.equals(EQUAL)) {
if (isId()) {
if (obj.getId() == Long.parseLong(valueToCompare)) {
return true;
}
} else if (isName()) {
if (obj.getName().equals(valueToCompare)) {
return true;
}
} else if (isSalary()) {
if (obj.getSalary() == Long.parseLong(valueToCompare)) {
return true;
}
} else {
System.err.println(UserMessage.INVALIDCOLUMN_NAME);
}
} else if (expression.equals(NOT_EQUAL)) {
if (isId()) {
if (!(obj.getId() == Long.parseLong(valueToCompare))) {
return true;
}
} else if (isName()) {
if (!(obj.getName().equals(valueToCompare))) {
return true;
}
} else if (isSalary()) {
if (!(obj.getSalary() == Long.parseLong(valueToCompare))) {
return true;
}
} else {
System.err.println(UserMessage.INVALIDCOLUMN_NAME);
}
} else if (expression.equals(GREATER)) {
if (isId()) {
if ((obj.getId() > Long.parseLong(valueToCompare))) {
return true;
}
} else if (isSalary()) {
if ((obj.getSalary() > Long.parseLong(valueToCompare))) {
return true;
}
} else {
System.err.println(UserMessage.INVALIDCOLUMN_NAME);
}
} else if (expression.equals(LESSER)) {
if (isId()) {
if ((obj.getId() < Long.parseLong(valueToCompare))) {
return true;
}
} else if (isSalary()) {
if ((obj.getSalary() < Long.parseLong(valueToCompare))) {
return true;
}
} else {
System.err.println(UserMessage.INVALID_IDENTIFIER);
}
}
return false;
}
Let me know if you want to see any other codes.
I just want to know,
In the first place LinkedList is correct data structure to use ? Is this performs well ?? Any enhancements to perform well ?
Any better way to achieve this ?
here are few example queries:
select * where ID > 100
select * where Name != Ramesh
select * where Salary < 500000
select Name order by Name
select ID
Thanks for any help. Bounty will be offered after 2 days. I can't do that now.
Note2: This is a test to check my data manage skills and I cannot use any database.
No, this does not perform well at all. You are searching through N employees every time. So if you have 1 million employees, you will search all 1 million employees before returning the correct employee. Even worst, if it doesn't exist, you will have to search exhaustibly before you can know if it exists.
Is this for use in production? If so then just use SQLite or some other simple database. You want to write once and read multiple times with indexes. I cannot stress enough that what you are writing will have bugs and instead you should use something that was already tested.
Assuming this is not for production and you are just having fun, then you want to emulate what databases do in real life. They create indexes. Indexes are usually best described as Map<String, List<Employee>>.
The idea is that initially reading the data from disk is expensive. But you read it once. For each dimension, Name, Salary, ID, etc... you want create separate indexes.
So let's say you were creating an index of all employees by ID. You would want to do something like:
Map<String, Employee> employeesById = new HashMap<>();
for(Employee e : employees) {
employeesById.put(e.getId(), e);
}
The above assumes that employee ids are unique. If they are not then you would need create a List<Employee>. For example for index by name:
Map<String,List<Employee>> employeesByName = new HashMap<>();
for(Employee e : employees) {
employeesByName.get(e.getName()).add(e); // Make sure to create the array if it doesn't exist
}
So now, for reading, let's say you get SELECT * FROM employees where id = 123; you can simply just return employeesById.get("123").
This solution is O(1). As the file gets bigger, you will not have any performance loss. This is probably the fastest solution.
To add onto Amir's answer, you can also use a TreeMap<> instead of a HashMap<>. Databases normally don't create indexes as hash maps but as balanced binary trees, which is what Java's TreeMap<> class is.
http://docs.oracle.com/javase/8/docs/api/java/util/TreeMap.html
HashMap<> has O(1) lookup on keys, but is exact match on key only. TreeMap<> has O(log n) lookup on keys, but allows ranged lookups higherKey, lowerKey) and map partitioning on key range (subMap).
The problem of duplicates can either be solved by not allowing them (unique key) or storing values in a list and linear search on the subset (non-unique key).
Assuming you are not interested in any of the in-memory database solution and using Java 8,
You should convert all your conditions to predicate and apply them on the stream . This will take advantage of Java 8's parallelism feature http://blog.takipi.com/new-parallelism-apis-in-java-8-behind-the-glitz-and-glamour/
So in short your code can be much cleaner and faster
public static Predicate<Employee> isSalaryGreaterThan(Integer salary) {
return p -> p.getSalary() > salary;
}
Predicate predicate1 = isSalaryGreaterThan(50000)
employeeList.stream().filter(predicate1).filter(predicate2)...collect(Collectors.<Employee>toList())

JPA Criteria Query API and order by null last

My problem is null values must be last order by statement. My code snipshot below. I use javax persistance criteria builder. My query complicated.
import javax.persistence.criteria.CriteriaBuilder;
public Predicate getSomePredicate() {
Predicate predicate = cb.conjunction();....
...predicate.getExpressions().add(cb.and(cb.or(cb.and(v1, v2), cb.and(s1, s2))));
EOrderByType orderType = EOrderByType.values()[orderBy]
;
switch (orderType) {
case PRICE: cq.where(predicate).orderBy(cb.asc(root.get("price")));
break;
case PRICE_HIGH_TO_LOW: cq.where(predicate).orderBy(cb.desc(root.get("price")));
break;
case CONSUPTION: cq.where(predicate).orderBy(cb.desc(root.get("consume")));
break;
default:
break;
}
return cq.getRestriction();
}
How to achieve order by price null last with criteria builder ?
Hi I almost search all internet pages and then find a solution, you can write switch case order by part. like below: to order by desc if price is null, price value is 1000000, and to order by asc if price is null, price value is 0. if you want these, you can write expression like below.
EOrderByType orderType = EOrderByType.values()[orderBy];
Expression<Object> queryCase = cb.selectCase().when(cb.isNull(root.get("price")), 100000000).otherwise(root.get("price"));
Direction dir = Direction.ASC;
switch (orderType) {
case UCUZDAN_PAHALIYA:
queryCase = cb.selectCase().when(cb.isNull(root.get("price")), 100000000).otherwise(root.get("price"));
break;
case PAHALIDAN_UCUZA:
queryCase = cb.selectCase().when(cb.isNull(root.get("price")), 0).otherwise(root.get("price"));
dir = Direction.DESC;
break;
}
cq.where(predicate).orderBy(direction( cb, queryCase, dir));
This is a bit of an extension to katsu's answer to his own question. I was trying to find a solution to being able to sort most of the columns of a table where some columns are allowed to have null values. I wanted to sort the null values in front of the lowest non-null values when sorting in ascending order and after the lowest non-null values when sorting in descending order. In other words, pretty much the opposite of the (Oracle's) default behavior.
I found other methods that might do this, but this one didn't require me to go outside of Hibernate and JPA 2 persistence, but still get the results I wanted. This is a snippet of code taken from my actual code, but consolidated in one spot and with some names changed. Any syntax, compilation-type errors you see are probably due to that.
// sortByColumn is a String containing the Hibernate version of the column name, which had
// been assigned as the ID of the table header column of the column by which we are sorting.
// sortAscending is a Boolean object containing Boolean.TRUE if we are to sort in ascending
// order or Boolean.FALSE or null if we are to sort in descending order. This may seem a
// bit odd, but in the case we need this for, the default sort column is a release date and
// reverse chronological order is the most useful in that case.
// Also defined are: CriteriaQuery<SoftwareVersion> criteriaQuery and
// CriteriaBuilder criteriaBuilder by the typical means.
final Root<SoftwareVersion> softwareVersionRoot =
criteriaQuery.from(SoftwareVersion.class);
private static final String EMPTY_STRING = "";
if (sortByColumn != null && sortByColumn.trim().length() > 0) {
Order sortOrder;
Expression<String> sortColumnExpression;
if (sortByColumn.equalsIgnoreCase(SoftwareVersion_.installationFileLength.getName()) ||
sortByColumn.equalsIgnoreCase(SoftwareVersion_.releaseTimestamp.getName())) {
// The two non-String fields (exposed to the user) that we don't need to have the
// lower() function operate upon.
sortColumnExpression = oemSoftwareVersionRoot.get(sortByColumn);
} else {
// We use the lower() function to enforce case insensitive sorting on the columns we
// show to the user, which are all Strings except as noted above.
Expression<String> rootExpression = oemSoftwareVersionRoot.get(sortByColumn);
sortColumnExpression = criteriaBuilder.lower(rootExpression);
}
// The columns for installation file name, installation file length and release timestamp
// are just three of the columns that we allow the user to sort by. However, these three
// may have null values in the database, and require some special handling.
if (sortByColumn.equalsIgnoreCase(SoftwareVersion_.installationFileLength.getName()) ||
sortByColumn.equalsIgnoreCase(SoftwareVersion_.installationFileName.getName()) ||
sortByColumn.equalsIgnoreCase(SoftwareVersion_.releaseTimestamp.getName())
) {
Expression<Object> queryCase;
if (sortByColumn.equalsIgnoreCase(SoftwareVersion_.installationFileName.getName())) {
// Installation file name is a (case insensitive) String
queryCase = criteriaBuilder.selectCase().when(
criteriaBuilder.isNull(sortColumnExpression),
StringUtil.EMPTY_STRING).otherwise(sortColumnExpression);
} else if (sortByColumn.equalsIgnoreCase(SoftwareVersion_.releaseTimestamp.getName())) {
// Release timestamp is a database timestamp
LocalDateTime dateTime = LocalDateTime.of(1970,1,1,0,0);
// Equivalent to Unix epoch time. Note month is 1-12, not 0-11
queryCase = criteriaBuilder.selectCase().when(
criteriaBuilder.isNull(sortColumnExpression),
Timestamp.valueOf(dateTime)).otherwise(sortColumnExpression);
} else {
// Installation file length is a Long (or BigDecimal) computed when the file is uploaded.
// The user can't set or change it, but can sort by it.
queryCase = criteriaBuilder.selectCase().when(
criteriaBuilder.isNull(sortColumnExpression),
Long.valueOf(0)).otherwise(sortColumnExpression);
}
if (asc != null && asc.booleanValue()) {
sortOrder = criteriaBuilder.asc(queryCase);
} else {
sortOrder = criteriaBuilder.desc(queryCase);
}
} else {
if (asc != null && asc.booleanValue()) {
sortOrder = criteriaBuilder.asc(sortColumnExpression);
} else {
sortOrder = criteriaBuilder.desc(sortColumnExpression);
}
}
criteriaQuery.orderBy(sortOrder);
}

How can I ensure that a method returns a value?

The method I have written below is supposed to act on a BinaryTreeNode to flatten the tree 'beneath' that node. My if-else if-else together with a recursive (?) structure, to my understanding, will always return a value, but I am getting an error in Eclipse saying "This method must return a result of type <Integer>.
After doing research, I believe that Java cannot quite tell that the method will always return a correct value, since the return statement is in an 'else'. Is this the problem? How can I alternatively design the method to avoid this problem?
//doFlatten acts on a BinaryTreeNode and takes a storage list as an argument
//it will call itself on any children on the node
//if the node is a leaf, it will update the storage list and return that updated list
public List<Integer> doFlatten(List<Integer> result){
if (this.leftChild != null){
this.leftChild.doFlatten(result);
}
else if (this.rightChild != null){
this.rightChild.doFlatten(result);
}
else{
result.add(this.value); //add leaf to result list
return result;
}
}
Make the return type void and remove return result. There's no need to return the result object, since it's the same result object that was passed in (the caller already has a reference to it).
The best bet is to define the a variable with the return type of the method and initialize it a default value, assign the proper value of the result in the method, and in the end, as the last line of the method, return this variable.
For your method, it may look like this:
public List<Integer> doFlatten(List<Integer> result) {
List<Integer> realResult = new ArrayList<>(result);
if (this.leftChild != null){
this.leftChild.doFlatten(result);
}
else if (this.rightChild != null){
this.rightChild.doFlatten(result);
}
else{
result.add(this.value); //add leaf to result list
realResult.add(this.value);
//avoid return statement here
//return result;
}
//single point for return statement
return realResult;
}
But, for this case, as you can see in code above, it seems meaningless to even return a result because the proper result of this method is stored in List<Integer> result. So, just make your method void:
public void doFlatten(List<Integer> result) {
//rest of your code...
}
Your method actually doesn't always return a value (the first if and first else) don't have a return.
This seems to be what you want:
public List<Integer> doFlatten(List<Integer> result){
if (this.leftChild != null){
this.leftChild.doFlatten(result);
}
else if (this.rightChild != null){
this.rightChild.doFlatten(result);
}
else{
result.add(this.value); //add leaf to result list
}
return result;
}
Examine your code again. You have only one return statement in the last else branch. This means that your method returns value only if it arrives to this point. This is exactly what compiler reports you.
So, the question "how to ensure that my method returns value" can be answered like "compile your code". If you managed to compile code be sure that your method indeed returns value or throws exception.
If however you are actually asking about the best coding practices that help you to avoid such compilation errors IMHO there is no one 100% correct answer.
See the recommendations of Luigi Mendoza. In some cases they are good. However (sorry, Luigi) I cannot agree that they always good. I'd say that you should avoid if/else structures when it is possible. For example series of if statements with return in the end of if block in some cases more readable.
I think you just want :
//doFlatten acts on a BinaryTreeNode and takes a storage list as an argument
//it will call itself on any children on the node
//if the node is a leaf, it will update the storage list and return that updated list
public List<Integer> doFlatten(List<Integer> result){
if (this.leftChild != null){
return this.leftChild.doFlatten(result);
}
else if (this.rightChild != null){
return this.rightChild.doFlatten(result);
}
else{
result.add(this.value); //add leaf to result list
return result;
}
}
Notice that in my version, all predicate outcomes lead to a List<Integer> being returned, where in your case, only the else clause does.

DFS tree traversal function modification

Please find below my implementation for DFS.
protected void DFS(String search) {
for(Tree<T> child : leafs) {
if(child.value.equals(search))
return;
else
child.DFS(search);
System.out.println(child.value);
}
}
The objective is to stop traversal on finding the node whose value is in the variable search. However, the above function goes on traversing the tree even beyond the declared search node. Could someone help me modify the above function?
Thank you.
Edit 1
protected boolean DFS(String anaphorKey) {
boolean found = false;
for(Tree<T> child : leafs) {
if(child.head.equals(anaphorKey))
return true;
found = child.DFS(anaphorKey);
if(found == true)
break;
System.out.println(child.head);
//System.out.println("anaphorKey: "+anaphorKey);
}
return found;
}
Tried implementing the given answer suggestion (#SJuan76). The implementation above isn't working as desired. Could you point me to the place where code is not as per the logic suggested?
rookie, might I suggest an implementation using the classic for-loop (as opposed to the enhanced for-loop being used now) which allows integration of your stop-condition a bit better, something like:
protected boolean DFS(String key) {
boolean found = false;
for(int i = 0; i < leafs.size() && !found; i++) {
Tree<T> child = leafs.get(i);
if(child.head.equals(key))
found = true;
else
found = child.DFS(key);
}
return found;
}
So as soon as your found condition is hit, the 'found' becomes true and your loop stops.
What you may have forgotten is the "found = child.DFS(key)" portion of the recursion, where you need to remember the result of your recursive calls so ALL your for-loops on up the chain all break as soon as you return.
Hope that helps.
Option A (Nice): the function returns a value, when the node is found it returns a different value that if the node was not found. When you call to method, if you get the found value you stop the loop and return the found value too.
Option B (Ugly): When found, thow an Exception (better if it is your own implementation of it). Don't forget to catch it.
Option C (Uglier): The same with global (static) variables.
UPDATE 1:
It looks like your method should run ok now, can you check (System.out.println) if your value is ever found?
In a more personal opinion, I would find
protected boolean DFS(String anaphorKey) {
for(Tree<T> child : leafs) {
if(child.head.equals(anaphorKey))
return true;
if(child.DFS(anaphorKey)) // No need to store value. No need to check == true (it is implicit)
return true; // If we are in this line the value was found, always return true
System.out.println(child.head);
//System.out.println("anaphorKey: "+anaphorKey);
}
return false; // If the method did not exit previously it was because the value was not found, so in this line always return false
}
more readable (but it should work exactly as your implementation)

JPA getSingleResult() or null

I have an insertOrUpdate method which inserts an Entity when it doesn't exist or update it if it does. To enable this, I have to findByIdAndForeignKey, if it returned null insert if not then update. The problem is how do I check if it exists? So I tried getSingleResult. But it throws an exception if the
public Profile findByUserNameAndPropertyName(String userName, String propertyName) {
String namedQuery = Profile.class.getSimpleName() + ".findByUserNameAndPropertyName";
Query query = entityManager.createNamedQuery(namedQuery);
query.setParameter("name", userName);
query.setParameter("propName", propertyName);
Object result = query.getSingleResult();
if (result == null) return null;
return (Profile) result;
}
but getSingleResult throws an Exception.
Thanks
Throwing an exception is how getSingleResult() indicates it can't be found. Personally I can't stand this kind of API. It forces spurious exception handling for no real benefit. You just have to wrap the code in a try-catch block.
Alternatively you can query for a list and see if its empty. That doesn't throw an exception. Actually since you're not doing a primary key lookup technically there could be multiple results (even if one, both or the combination of your foreign keys or constraints makes this impossible in practice) so this is probably the more appropriate solution.
Try this in Java 8:
Optional first = query.getResultList().stream().findFirst();
I encapsulated the logic in the following helper method.
public class JpaResultHelper {
public static Object getSingleResultOrNull(Query query){
List results = query.getResultList();
if (results.isEmpty()) return null;
else if (results.size() == 1) return results.get(0);
throw new NonUniqueResultException();
}
}
Here's a good option for doing this:
public static <T> T getSingleResult(TypedQuery<T> query) {
query.setMaxResults(1);
List<T> list = query.getResultList();
if (list == null || list.isEmpty()) {
return null;
}
return list.get(0);
}
I've done (in Java 8):
query.getResultList().stream().findFirst().orElse(null);
From JPA 2.2, instead of .getResultList() and checking if list is empty or creating a stream you can return stream and take first element.
.getResultStream()
.findFirst()
.orElse(null);
Spring has a utility method for this:
TypedQuery<Profile> query = em.createNamedQuery(namedQuery, Profile.class);
...
return org.springframework.dao.support.DataAccessUtils.singleResult(query.getResultList());
If you wish to use the try/catch mechanism to handle this problem.. then it can be used to act like if/else. I used the try/catch to add a new record when I didn't find an existing one.
try { //if part
record = query.getSingleResult();
//use the record from the fetched result.
}
catch(NoResultException e){ //else part
//create a new record.
record = new Record();
//.........
entityManager.persist(record);
}
Here's a typed/generics version, based on Rodrigo IronMan's implementation:
public static <T> T getSingleResultOrNull(TypedQuery<T> query) {
query.setMaxResults(1);
List<T> list = query.getResultList();
if (list.isEmpty()) {
return null;
}
return list.get(0);
}
There is an alternative which I would recommend:
Query query = em.createQuery("your query");
List<Element> elementList = query.getResultList();
return CollectionUtils.isEmpty(elementList ) ? null : elementList.get(0);
This safeguards against Null Pointer Exception, guarantees only 1 result is returned.
So don't do that!
You have two options:
Run a selection to obtain the COUNT of your result set, and only pull in the data if this count is non-zero; or
Use the other kind of query (that gets a result set) and check if it has 0 or more results. It should have 1, so pull that out of your result collection and you're done.
I'd go with the second suggestion, in agreement with Cletus. It gives better performance than (potentially) 2 queries. Also less work.
Combining the useful bits of the existing answers (limiting the number of results, checking that the result is unique) and using the estabilshed method name (Hibernate), we get:
/**
* Return a single instance that matches the query, or null if the query returns no results.
*
* #param query query (required)
* #param <T> result record type
* #return record or null
*/
public static <T> T uniqueResult(#NotNull TypedQuery<T> query) {
List<T> results = query.setMaxResults(2).getResultList();
if (results.size() > 1) throw new NonUniqueResultException();
return results.isEmpty() ? null : results.get(0);
}
The undocumented method uniqueResultOptional in org.hibernate.query.Query should do the trick. Instead of having to catch a NoResultException you can just call query.uniqueResultOptional().orElse(null).
I solved this by using List<?> myList = query.getResultList(); and checking if myList.size() equals to zero.
Look this code :
return query.getResultList().stream().findFirst().orElse(null);
When findFirst() is called maybe can be throwed a NullPointerException.
the best aproach is:
return query.getResultList().stream().filter(Objects::nonNull).findFirst().orElse(null);
Here's the same logic as others suggested (get the resultList, return its only element or null), using Google Guava and a TypedQuery.
public static <T> getSingleResultOrNull(final TypedQuery<T> query) {
return Iterables.getOnlyElement(query.getResultList(), null);
}
Note that Guava will return the unintuitive IllegalArgumentException if the result set has more than one result. (The exception makes sense to clients of getOnlyElement(), as it takes the result list as its argument, but is less understandable to clients of getSingleResultOrNull().)
Here's another extension, this time in Scala.
customerQuery.getSingleOrNone match {
case Some(c) => // ...
case None => // ...
}
With this pimp:
import javax.persistence.{NonUniqueResultException, TypedQuery}
import scala.collection.JavaConversions._
object Implicits {
class RichTypedQuery[T](q: TypedQuery[T]) {
def getSingleOrNone : Option[T] = {
val results = q.setMaxResults(2).getResultList
if (results.isEmpty)
None
else if (results.size == 1)
Some(results.head)
else
throw new NonUniqueResultException()
}
}
implicit def query2RichQuery[T](q: TypedQuery[T]) = new RichTypedQuery[T](q)
}
So all of the "try to rewrite without an exception" solution in this page has a minor problem. Either its not throwing NonUnique exception, nor throw it in some wrong cases too (see below).
I think the proper solution is (maybe) this:
public static <L> L getSingleResultOrNull(TypedQuery<L> query) {
List<L> results = query.getResultList();
L foundEntity = null;
if(!results.isEmpty()) {
foundEntity = results.get(0);
}
if(results.size() > 1) {
for(L result : results) {
if(result != foundEntity) {
throw new NonUniqueResultException();
}
}
}
return foundEntity;
}
Its returning with null if there is 0 element in the list, returning nonunique if there are different elements in the list, but not returning nonunique when one of your select is not properly designed and returns the same object more then one times.
Feel free to comment.
I achieved this by getting a result list then checking if it is empty
public boolean exist(String value) {
List<Object> options = getEntityManager().createNamedQuery("AppUsers.findByEmail").setParameter('email', value).getResultList();
return !options.isEmpty();
}
It is so annoying that getSingleResult() throws exceptions
Throws:
NoResultException - if there is no result
NonUniqueResultException - if more than one result
and some other exception that you can get more info on from their documentation
I prefer #Serafins answer if you can use the new JPA features, but this is one fairly straight forward way to do it which I'm surprised hasn't been mentioned here before:
try {
return (Profile) query.getSingleResult();
} catch (NoResultException ignore) {
return null;
}
`public Example validate(String param1) {
// TODO Auto-generated method stub
Example example = new Example();
Query query =null;
Object[] myResult =null;
try {
query = sessionFactory.getCurrentSession()
.createQuery("select column from table where
column=:p_param1");
query.setParameter("p_param1",param1);
}
myResult = (Object[])query.getSingleResult();//As your problem occurs here where the query has no records it is throwing an exception
String obj1 = (String) myResult[0];
String obj2 = (String) myResult[1];
example.setobj1(ISSUtil.convertNullToSpace(obj1))
example.setobj2(ISSUtil.convertNullToSpace(obj2));
return example;
}catch(Exception e) {
e.printStackTrace();
example.setobj1(ISSUtil.convertNullToSpace(""));//setting
objects to "" in exception block
example.setobj1(ISSUtil.convertNullToSpace(""));
}
return example;
}`
Answer : Obviously when there is no records getsingleresult will throw an exception i have handled it by setting the objects to "" in the exception block even though it enter the exception you JSON object will set to ""/empty
Hope this is not a perfect answer but it might help
If some needs to modify my code more precisely and correct me always welcome.
Thats works to me:
Optional<Object> opt = Optional.ofNullable(nativeQuery.getSingleResult());
return opt.isPresent() ? opt.get() : null;

Categories