Mismatching return of a query with NamedQuery - java

Hi to all i'm new in J2EE world.
I'm trying to use #Namequery to get a List of String from my model(the class is called Element), in this case the attribute name.
Why when I use #NamedQuery(name="Element.findAllNames",query="SELECT e.name FROM Element e")
and I use it on my ElementMgrBean using:
public List<String> getAllElementsName() {
return em.createNamedQuery(Element.FIND_ALLNAMES,Element.class).getResultList();
}
the result appears to be a list of elements instead of a list of String as I expected.
Someone can explain me why Java says: "Type mismatch: cannot convert from List of Element to List of String"??
PS: I have defined:public static final String FIND_ALLNAMES = "Element.findAllNames";

When you write em.createNamedQuery("NameOfNamedQuery", MyClass.class), you say you want to fetch MyClass instances (in your query MyClass==Element). The problem is now, that your query SELECT e.name FROM Element e returns Strings instead of Element instances (as the e.name fields are of type Strings).
In order to correct the problem you either correct the call to em.createNamedQuery(Element.FIND_ALLNAMES, String.class) (the preferred solution, as it returns a TypedQuery<String> instance), or you remove the second parameter: em.createNamedQuery(Element.FIND_ALLNAMES) (in this case you are not type-safe anymore, as it returns a Query instance).

Related

How to query Grakn with Java?

I went through the documentation of Java api to query Grakn database.
Grakn.Transaction readTransaction = session.transaction(GraknTxType.READ);
GetQuery query = Graql.match(var("p").isa("person")).limit(10).get();
Stream<ConceptMap> answers = query.withTx(readTransaction).stream();
answers.forEach(answer -> System.out.println(answer.get("p").id()));
It's printing id, but I want to see the data, the name associated with the person. I want to see the content inside the result. It's simply showing id.
The answers provided as the result of a Graql query, is a collection of the variables (and their values) as you have specified them in the query itself.
In this case, to get the name of instances of person, you'd include it in the query like so:
GetQuery query = Graql.match(var("p").isa("person").has("name", var("n"))).limit(10).get();
The Graql equivalent being match $p isa person, has name $n; get;.
Now you can use the methods available in the Concept API to retrieve information available on each variable.
In this case, variable n holds an attribute and you'd want to retrieve its value(), like so:
answers.forEach(answer -> System.out.println(answer.get("n").asAttribute().value()))

setParameterList() does not return full result set

I want to make my small spring project effectively. So I use IN clause instead of using loops in hql.
01) Question in setParameterList()
To use setParameterList(), we have to pass list object
List<Department> listDeptmntId = reportService.listDepartmentID(companyId); //list of objects
String hql = "select s.department.departmentName, g.dateTime from Gauge g inner join g.survey s where s.department in (:dpts)";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setParameterList("dpts",listDeptmntId);
The query works fine. But this return only one (first object in listDeptmntId list) resultset, does not return other results.
I tries to pass integer list like [1,2,3] using following method also not working.
List<Integer> dptIds=listDeptmntId.stream().map((Department::getDepartmentId()).collect(Collectors.toList());
02) Question in setParameter()
int cId=10;
String hql="...... companyId=:id"
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setParameter("id",cId);
Sometime when I use parameter passing ("=:") , it does not work for Integers . But directly setting variable to query like following is working
int cId=10;
String hql="...... companyId="+cId
Query query = sessionFactory.getCurrentSession().createQuery(hql);
My code may be wrong because I'm going through ebooks and referring materials to do the project. Thank you in advance.
I generally do IN(?, ..., ?) using an java.sql.Array.
long[] deptIds = listDeptmntId.toArray(new long[listDeptmntId.size()];
java.sql.Array array = conn.createArrayOf("LONG", deptIds);
query.setPameter("depts", array);
q1) Check the join (can't see any other reasons to return just one object). And passing [1,2,3] won't work with that query because in query you're dealing with department object. If you want [1,2,3] to work change the query to check for dept-ids like this -> "select s.department.departmentName, g.dateTime from Gauge g inner join g.survey s where s.department.id in (:id-list)"
q2) You've already created the query object when you set the parameter, so setting parameter at that point might not affect the query object. (Your "+" approach works since the parameter is set to the query when creating the query object.)

Can we get single object from hql query?

I am writing a select query in hql , my task is to activate the bus. First I will get a messege from client as busId#busStatus, so first I look for this perticular busId is active or inactive So I have to write select query but in hibernate query.list() returns list. Here I think list is unnecessary , a single object is enough .
Here is my code ,
String hql="from BusDetailBean where Busid= :busId and bus_status=:busStatus";
Query query = session.createQuery(hql);
query.setParameter("busId", busId);
query.setParameter("busStatus", busStatus);
List<BusDetailBean> busDetails=(List<BusDetailBean>)query.list();
if(busDetails.isEmpty())
{
//my other stuff
}
else
{
//bus ativation stuff
}
My question is the select query returns only one object if list is not empty I have to use for loop in else part. So how can I optimise this code. can anyone help me in this.
You can use query.getSingleResult()
You can use query.setMaxResults(1);
You can get the object at index 0 in the list:
List l = query.list()
if (l.size()>0) {
return l.get(0)
}
I don't think persitence should be mixed with business logic.
What about returning Optional from the persitence layer and whether result is present/absent do something in higher level?
In persistance layer something like:
return query.list()
.stream()
.findFirst()
This, according to docs, will return first result or empty optional if the collection was empty.
And then:
Optional<Bus> optionalBus = repository.find(busId, busStatus);
if (optionalBus.isPresent()) {
something here
} else {
something else
}
by using query.uniqueResult() you don't ensure that if you have many results , then you will get only one of them.
With uniqueResult() you place a guard/contraint at your result set to be aware that this query should always return a unique result.
For this type of problem, the out of the box solution in Hibernate is to use the uniqueResult() method in the Query class:
public Object uniqueResult()
From the Hibernate JavaDocs:
Convenience method to return a single instance that matches the query,
or null if the query returns no results.
Returns: the single result or null
Throws:
NonUniqueResultException - if there is more than one matching result
HibernateException

ClassCastException on converting List to Object<class>?

I am trying to retrieve the values from database and storing it in List,
The data's are retrieved and working properly, But when i convert the List into Object<pojo class> i am getting an Exception ,
My Code is
Query qry=session.createQuery("select personaldetails.fname,personaldetails.lname from Personaldetails as personaldetails where refId=1001");
List<Personaldetails> l=(List<Personaldetails>)qry.list();
session.getTransaction().commit();
session.close();
System.out.println("--->"+l.size()); //List 'l' holds the values from DB
Personaldetails p; //This is an pojo class
p=(Personaldetails)l.get(i); //Here i am getting the exception here
System.out.println("Person name "+p.getFname());
In above mentioned line i got Exception as ClassCastException , i don't know why, i tried it shows no error while compiling.
Any suggestion will be appreciated....
I see that you are doing selective query - that is select fname, lname
select personaldetails.fname,personaldetails.lname from Personaldetails as personaldetails where refId=1001
which returns List<Object[]> where each elements in array represents the 2 column values
List will be something like [{"Fname1", "LName1"}, {"Fname2", "Lname2"}]
So ClassCastException is due to the fact that you are converting Object[] into PersonDetails.
To expect List<PersonDetails> as the result, you can use query like
select from Personaldetails as personaldetails where refId=1001
Or you can iterate through the List<Object[]> and construct PersonDetails yourself
for(Object[] arr : l) {
PersonDetails p = new PersonDetails();
p.setFName(arr[0]);
p.setLName(arr[1]);
}
I prefer the first approach
In above mentioned line i got Exception as ClassCastException , i
don't know why, i tried it shows no error while compiling.
When you explicitly cast, the compiler cannot help you. Type casting is your way to tell the compiler that you know this type is some other type. The compiler trusts that you know what you're doing.
The real question here is how does the list get created?
Query qry=session.createQuery("select personaldetails.fname,personaldetails.lname from Personaldetails as personaldetails where refId=1001");
List<Personaldetails> l=(List<Personaldetails>)qry.list();
How do you know that qry.list() returns a List? You just ran a SQL statement and jumped to a List. Since the cast to List works fine, clearly a List is in fact returned (though due to type erasure, we don't know if it in fact only holds Personaldetails objects).
It must return a List. #sanbhat seems to have pointed you to the right structure for that method. I don't have any experience with Hibernate.

JAVA: NamedQuery String problem

Hello guys I am having some problems with exact matches while doing a NamedQuery.
I am currently using something like this:
#NamedQuery(name = MyClass.GET_ENTRY_BY_NAME, query = "select e from Entry e where e.name =:"+ Entry.NAME )
...
Query query = em.createNamedQuery(MyClass.GET_ENTRY_BY_NAME);
query.setParameter(Entry.NAME, myEntry.getName());
It works for most cases, however I noticed that in case the user pass the file name with an space at the end, the namedQuery ignores that character. For example:
Query query = em.createNamedQuery(MyClass.GET_ENTRY_BY_NAME);
query.setParameter(Entry.NAME, myEntry.getName()+ " ");
Will return the same result as the query before. Bypassing my 'valid entry' validation. In other words I'd like the query to return no entry at all and treat the error later on.
One workaround I could think of, is to put single quotes surrounding my parameter in the namedQuery, like this:
#NamedQuery(name = MyClass.GET_ENTRY_BY_NAME, query = "select e from entry e where e.name =':"+ Entry.NAME "'")
However it will trash my code in case the String contains single quotes in it...
Any ideas guys?
I guess this happens because your database field is declared as CHAR(...), and therefore stored values are padded with whitespaces which are not taken into account by = operation.
So, you may either declare your database field as VARCHAR(...) or use a built-in trim function:
query = "select e from Entry e where trim(trailing from e.name) =:"+ Entry.NAME
I did some research in JPA and found out that it does some automatic trimming for CHARs, I am not sure if this behaves the same with Strings, but since it is happening to me... I believe so. The only way to bypass it is by setting some attribute within the session DatabaseLogin object (see http://www.eclipse.org/eclipselink/api/1.1/org/eclipse/persistence/sessions/DatabaseLogin.html#setShouldTrimStrings) .
Well I didn't want to be messing up with the session properties so I decided to make some sort of check and throwing the same exception as the NoResultException catch does in my code.
I basically took the result from the database and compared the field with the String I used:
query.setParameter(Entry.NAME, myEntry.getName());
...
if(!StringUtils.equals(result.getName(), myEntry.getName()){
do a cool throw just like NoResultException Catch
}
I also had to include the Trim function axtavt! This is just to make sure that if the database has a column with trailing spaces and it matches the parameter given by the user, it will be included as a valid answer. For example:
Database entry: Name = "Flavio " - Trimmed with Function = "Flavio".
Parameter passed: Name = "Flavio " - Trimmed by JPA automatic function = "Flavio".
If it isnt trimmed at all it will just Compare "Flavio " with "Flavio", returning NoResult when it was supposed to return that Entry.
Nasty workaround, but as long as there is no other way to stop the auto-trimming we will have to just make use of this sort of things.
Thanks for all the other answers!!

Categories

Resources