Can not understand the result of request JPA - java

I have a function that return an ArrayList< String > ,the list contain elements retrieved from database using JPA ,my problem is that I can't understand the format of the output!
the function is:
public ArrayList<String> getMyListEnvironment()
{
ArrayList<String> env=new ArrayList<String>();
try{
EntityTransaction entr=em.getTransaction();
entr.begin();
javax.persistence.Query multipleSelect= em.createQuery("SELECT h.hEnv FROM HPe h WHERE h.hPePK.pePlatform = :w ").setParameter("w", "platf1");
List s = new LinkedList();
s= multipleSelect.getResultList();
env = new ArrayList(s);
entr.commit();
return env;
}
catch (Exception e )
{
System.out.println(e.getMessage());
System.out.println("error");
}
finally {
em.close();
}
return env;
}
The output(Result):
[DTOMonito.HEnv[ envUrl=http://10.55.99.5:1055 ], DTOMonito.HEnv[ envUrl=http://10.55.99.99:8090 ]]

The query is returning the list of hEnv found as fields of the the HPe entity (seems like these abbreviations for the entities cause more confusion than good - it's a good idea to use descriptive names for these type of things).
Is HPe.hEnv a String? Perhaps your output is confusing because someone is storing a formatted string in this field. Without seeing your code, this is very hard to decipher.
Btw, this method is a bit wasteful for creating dead stores. There is absolutely no point in writing something like this:
List s = new LinkedList();
s= multipleSelect.getResultList();
You could save a line of code (and a LinkedList allocation) by just writing
List s = multipleSelect.getResultList();

Related

Criteria API throws exception instead of null [duplicate]

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;

Hibernate criteria, using associations to return results by restrictions

Hi guys i have this mapping inside the Customer entity:
#OneToOne(cascade={javax.persistence.CascadeType.ALL})
#JoinColumn(name="address")
private Address address;
And then i have this method in my DAO class:
#SuppressWarnings("unchecked")
public List<Customer> getCustomersFromThisAddress() throws Exception{
sessao = null;
try{
sessao = HibernateUtil.getSessionFactory().openSession();
Customer customer= new Customer();
Criteria criteria = sessao.createCriteria(customer.getClass())
.createAlias("address", "a")
.add(Restrictions.ilike("a.area", "bedford"));
return (List<Customer>) criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
} catch (Exception e) {
return null;
} finally {
sessao.close();
}
}
I would like to return all customers from the bedford area... I am new to Hibernate and Criteria, please help.
You have to remember about two things when using the ilike:
a) The underlying database must be able to support it or have an equivalent function.
b) Without specifying MatchMode or adding % symbols to the second argument, your statement is just a case-insensitive equals.
So if you want to search for a text that simply contains somewhere the bedford string then use one of the following:
.add(Restrictions.ilike("a.area", "%bedford%"));
or
.add(Restrictions.ilike("a.area", "bedford", MatchMode.ANYWHERE));
I was getting an empty list '[]' I realized that I made a mistake in the .add(Restriction.. line!!
the 'area' column data, in the Address table are all recorded as 'Bedford'..
after reading this: https://www.tutorialspoint.com/hibernate/hibernate_criteria_queries.htm
I found that I just needed to change
Criteria criteria = sessao.createCriteria(customer.getClass())
.createAlias("address", "a")
.add(Restrictions.ilike("a.area", "bedford"));
to
Criteria criteria = sessao.createCriteria(customer.getClass())
.createAlias("address", "a")
.add(Restrictions.like("a.area", "bedford"));
to return my list... Hope this will help others!!

Problems with deleting entities in EJB3

I have a question about deleting entities in EJB3.
I have two database tables: MainCategory and Category.
First, I have to find all MainCategory entitys' name and its Category, so I do this:
public List<MainCategory> findAllWithCategories() {
TypedQuery<MainCategory> query = em.createNamedQuery("MainCategory.findAll", MainCategory.class);
List<MainCategory> result = query.getResultList();
for (MainCategory mc : result){
try{
Hibernate.initialize(mc.getSubCategories());
}catch (Exception e){
e.printStackTrace();
}
}
return result;
}
Than I need its Categories, but I have to initialize something, so I do this (where selectedMainCategory is an element of List<MainCategory> = mainCategoryRepository.findAllWithCategories() )
List<Category> mainCategories = categoryRepository.findByMainCategoryIdAndInitialze(selectedMainCategory.getId());
instead of this:
List<Category> subCategories = mainCategory.getSubCategories();
And after some action I need to delete a Category, so I do (where selectedSubCategory is an element of subCategories):
selectedMainCategory.getSubCategories.remove(selectedSubCategory);
mainCategoryRepository.modify(selectedMainCategory);
However selectedSubCategory hasn't been removed from selectedMainCategory.getSubCategories().
Ok, I can remove it manually if I find it by Id and manually remove from the list, but I can't find out why getSubCategories.remove(object) doesn't work in this case. I guess it is something about equality of two java object, but I don't know exactly. How does EJB and Java work in this case? Can you explain it to me?

Embedded Array Retrieval Mongodb Java

I've been trying to get this query, but I have been unable to roll my heads over this one.
The Object looks like this:
{
restaurantName:'abc',
reviews:[
{
text:'Its awesome!'
person: 'John Doe'
}
{
text:'Nice Ambience'
person: 'Davis'
}
]
}
The intent is to find out all the reviews text present in the document. How do I do this using JAVA driver for Mongo. I keep getting Class Cast Exceptions
Following is the code:
Set fields = new TreeSet();
BasicDBList e ;
try {
DBObject dbObject;
while (cursor.hasNext()) {
doc = new Document();
e = (BasicDBList) cursor.next().get("reviews");
for(BasicDBObject temp: e){
fields.addAll(temp.keySet());
}
}
//System.out.println(cursor.next());
}
The error I am getting is:
Exception in thread "main" java.lang.ClassCastException: com.mongodb.BasicDBObject cannot be cast to java.util.ArrayList at org.poly.darshan.utils.DataExtractor.main(DataExtractor.java:57)
The code mentioned above intends to find the unique fields present in the sub-objects. But the problem is more or less the same.
Ok found the Solution. In my case I know the field names, so I can retrieve the DBObject and then check for each field name and typecast it accordingly to retrieve it. *Wonders how free the wonderland of Javascript is. Luckily in Java, we mostly always know what we are going to get.:)
The solution looks something like this:
while (cursor.hasNext()) {
doc = new Document();
e = cursor.next();
for (String field : e.keySet()) {
if (field.equals("reviews")) {
BSONObject temp = (BSONObject) e.get(field);
System.out.println(temp.toString());
}
//else print the other String values
}
}
If BSOONList is retrieved, then typecast it accordingly. BSONList may contain BSONList or BSONObject, so it gets messy if you dont know what you want to retrieve. Dynamic Typecasting is helpful in these cases.

How do you make query results available after closing the persistence manager

I am learning GAE and am getting a bit stuck. If I use the following, with a finally to make sure the persistence manager is closed, I get an exception when trying to actually read the Note objects:
public class Notes {
public List<Note> getAll() {
PersistenceManager pm = PMF.instance().getPersistenceManager();
try {
Query query = pm.newQuery("select from com.uptecs.google1.model.Note order by subject");
return (List<Note>) query.execute();
} finally {
pm.close();
}
}
}
The exception I get is this:
Object Manager has been closed
org.datanucleus.exceptions.NucleusUserException: Object Manager has been closed
at org.datanucleus.ObjectManagerImpl.assertIsOpen(ObjectManagerImpl.java:3876)
at org.datanucleus.ObjectManagerImpl.getFetchPlan(ObjectManagerImpl.java:376)
at org.datanucleus.store.query.Query.getFetchPlan(Query.java:497)
Try detaching the object from the graph with detachable="true":
#PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true")
public class Note {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long key;
...
}
Note: I totally understand the need for this, sometimes you need to retrieve the objects and lists in a controller, close the PM in the controller, then pass the models to the views. Until better solutions are known to me, this is what I am doing this on JDO/GAE with no problems so far.
List:
It seems to me that you will have to detach all the items in the list if you want to be able to use them after the PM is closed. I'd use this to get specific lists of items. A full getAll() can be very big in size.
public List<Note> getList(){
List<Note> detachedList=null, list=null;
try {
String query = "select from " + Note.class.getName();
pm = PMF.get().getPersistenceManager();
list = (List<Note>)pm.newQuery(query).execute();
detachedList = new ArrayList<Note>();
for(Note obj : list){
detachedList.add(pm.detachCopy(obj));
}
} finally {
pm.close();
}
return detachedList;
}
By Key:
public Note findByKey(Long key) {
Note detachedCopy=null, object=null;
try{
pm= PMF.get().getPersistenceManager();
object = pm.getObjectById(Note.class,key);
detachedCopy = pm.detachCopy(object);
}catch (JDOObjectNotFoundException e) {
return null; // or whatever
}
finally {
pm.close(); // close here
}
return detachedCopy;
}
Afer the close, you have a detached copy, with which you can work.
Reference: http://www.datanucleus.org/products/accessplatform_1_1/jdo/attach_detach.html
When result is returned in the list - objects are retrieved lazily (only when you ask for them). Since your persistence manager is closed you get an exception. By "detaching" the objects your are effectively telling the persistence manager to retrieve them eagerly.
In addition to the answer from bakkal, I would say that you absolutely need the detachable="true" annotation parameter, otherwise you will never get it to work.
To detach a list of objects, you can also use pm.detachCopyAll(your_query_result_list), wich will be a bit faster than your implementation of the iteration to detach, and will let you spare a few lines of code. Thanks JDO ! ;-) But be aware, this method requires explicit cast of its results.
Here's a working example I currently use in my last App (the Key used in the query is an Encoded String) :
pm = PMF.get().getPersistenceManager();
Query query = pm.newQuery(TandemSubscription.class);
query.setFilter("groupSubscriptionKey==groupSubscriptionKeyParam");
query.setOrdering("dateRDV desc");
query.declareParameters("String groupSubscriptionKeyParam");
// Get Data
#SuppressWarnings("unchecked")
List<TandemSubscription> savedSubscriptions =
(List<TandemSubscription>) query.execute(Key);
// Detach all objects in the list
savedSubscriptions =
(List<TandemSubscription>) pm.detachCopyAll(savedSubscriptions);
pm.close();
// Now you can use the list and its content.
I Hope this helps a bit.

Categories

Resources