I have a project in JavaEE, my task is to affect a professor to a form( a student placement form), I have an attribute called 'nb_sup' which is the number of student supervised by a selected professor, this number is incremented by one each time a professor is affected to a student. The problem is that my function sets the 'nub_sup' to one no matter how many times I affect the same professor.
Here is my code
public void SetNbSupPrfessor(Professor prof)
{
Query query = em.createQuery("update Professor u set nb_sup=:nb_sup WHERE u.id =:id");
query.setParameter("nb_sup", (1+ prof.getNb_sup()));
query.setParameter("id",prof.getId() );
query.executeUpdate();
}
It's safe to say that the professor inherits from the entity 'User' ,the 'nb_sup' is of type int and the 'id' is auto-increment.
I edited my code so this one worked
Professor prof = em.createQuery("select p from Professor p where p.id = :id",Professor.class)
.setParameter("id",id)
.getSingleResult();
prof.setNb_sup(prof.getNb_sup()+1);
em.merge(prof);
Related
I'm new to ORM interface, and I'm trying to connect to my databases with Hibernate.
What I've figured out so far is:
With a serializable object, I can get a persistent object with
Person p = session.get(Person.class, serializable);
I can get all the objects by a list with
List people = session.createQuery("FROM Person").list();
What I need is to find a row that meets a certain condition, such as SELECT * FROM person WHERE name="Kim" AND age=30;
However, the above two aren't the ways to achieve this.
#Entity
#Table(name = "person")
public class Person {
#Id
private Integer id; // I can use this variable when using session.get(Person.class, serializable) , but I cannot know the id of my target row.
private String name;
private Integer age;
...
Should I iterate all the objects in people, and check whether all the member variables match what I want?
Is there any simple way to achieve this?
First and most importantly, never put user input in a query like this
SELECT * FROM person WHERE name="Kim" AND age=30;
You have to use Prepared Statements. Learn why from Bobby Tables.
Secondly, you should use the JPA interface EntityManager instead of Hibernate's Session as the second one anchors you to a specific implementation, rather than the wider standard.
With the EntityManager you get an object by id like this:
Person p = em.find(Person.class, id);
To get a list of People you can create a JPQL query like this:
TypedQuery<Person> query = em.createQuery("SELECT p FROM Person p WHERE p.name = :name AND p.age = :age", Person.class);
query.setParameter("name", "Kim"); // :param1 defines a parameter named "param1" in the query
query.setParameter("age", 30);
List<Person> results = query.getResultList();
You could also do this in one chain if you don't need to reuse the query with different parameters on a loop.
List<Person> results = em.createQuery(..., Person.class)
.setParameter("name", "Kim")
.setParameter("age", 30)
.getResultList();
The reason to put every call on a new row is in case an exception occurs it will give you the proper row to look for. If they're all in one row, then that's not very useful.
If your query is a SELECT, and it needs to return exactly one result every time, you can use getSingleResult() instead of getResultList(). If you do that and the query did return more than one result, it will throw a NonUniqueResultException. If the query did not return any results it will throw a NoResultException instead of returning null.
If your query is NOT a SELECT, then you have to use executeUpdate() to invoke it after setting the parameters.
There are many resources to get you started, but generally if its for a Hibernate version before 5.2 you should consider it outdated, and it will likely be more difficult.
I'm new to JDOQL and I'm having troubles with the below. I'm trying to get the average salary for the department and then select the departments where the average salary is higher than a certain value.
Query averageSalaryByDep = pm.newQuery(Employee.class);
averageSalaryByDep.setResult("department, avg(salary)");
averageSalaryByDep.setGrouping("department");
Query qry = pm.newQuery(Department.class);
qry.setFilter("this.name == dep.name && averageSalary > 10000");
qry.declareVariables("Department dep, double averageSalary");
qry.addSubquery(averageSalaryByDep, "Department dep, double averageSalary", null);
The error message I'm currently getting:
javax.jdo.JDOUserException: Class name averageSalary could not be resolved
at org.datanucleus.api.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:636)
at org.datanucleus.api.jdo.JDOQuery.executeInternal(JDOQuery.java:391)
at org.datanucleus.api.jdo.JDOQuery.execute(JDOQuery.java:216)
A subquery has a single variable name (and returns a single thing). If unsure about something, put what the single-string query would look like (and the resultant SQL) and then it ought to be clear. The JDO spec has some useful examples IIRC
Regarding what you wanted to retrieve, I'd suggest you look at something more like
Query averageSalarySubq = pm.newQuery(Employee.class);
averageSalarySubq.setResult("avg(salary)");
averageSalarySubq.setFilter("this.department = :outerDepartment");
Query qry = pm.newQuery(Department.class);
qry.setFilter("averageSalary > 10000");
qry.declareVariables("double averageSalary");
qry.addSubquery(averageSalarySubq, "double averageSalary", null, "this");
which would equate to something like
SELECT FROM mydomain.Department WHERE
(SELECT AVG(e.salary) FROM mydomain.Employee e WHERE e.department = this) > 10000
hence subquery gets the average salary but joined to the outer query Department. Defining the SQL would reveal to you whether that is what you intend or not, but either way a subquery is for a single variable
I cannot find a solution to a problem that seems to be easy. Say there are 2 entity classes:
class A {
Set<B> bs;
}
class B {
String text;
}
How to create a criteria query that returns all A's that contains at least one B entity which fulfills a given condition (like b.text = 'condition')?
I think this link can be useful:
http://mikedesjardins.net/2008/09/22/hibernate-criteria-subqueries-exists/
It contains the following example about how create n exists criteria:
"What you’re really trying to do is to obtain all Pizza Orders where an associated small pizza exists. In other words, the SQL query that you’re trying to emulate is
SELECT *
FROM PIZZA_ORDER
WHERE EXISTS (SELECT 1
FROM PIZZA
WHERE PIZZA.pizza_size_id = 1
AND PIZZA.pizza_order_id = PIZZA_ORDER.pizza_order_id)
The way that you do that is by using an “exists” Subquery, like this:
Criteria criteria = Criteria.forClass(PizzaOrder.class,"pizzaOrder");
DetachedCriteria sizeCriteria = DetachedCriteria.forClass(Pizza.class,"pizza");
sizeCriteria.add("pizza_size_id",1);
sizeCriteria.add(Property.forName("pizza.pizza_order_id").eqProperty("pizzaOrder.pizza_order_id"));
criteria.add(Subqueries.exists(sizeCriteria.setProjection(Projections.property("pizza.id"))));
List<pizzaOrder> ordersWithOneSmallPizza = criteria.list();
And voila, the result will contain two PizzaOrders!"
Currently, I have an HQL query that returns all Members who possess ANY Award from a set of specified Awards:
from Member m left join m.awards as a where a.name in ("Trophy","Ribbon");
What I now need is HQL that will return all Members who possess ALL Awards specified in the set of Awards.
So, assuming this data:
Joe has Trophy, Medal
Sue has Trophy, Ribbon
Tom has Trophy, Ribbon, Medal
The query above would return Joe, Sue, and Tom because all three possess at least one of Trophy or Ribbon. But I need to return only Sue and Tom, because they are the only ones who possess all of the specified awards (Trophy and Ribbon).
Here's the class structure (simplified):
class Member {
private String name;
private Set<Award> awards;
}
class Award {
private String name;
}
select m from Member m left join m.awards as a where a.name in ("Trophy","Ribbon") group by m having count(a)=2
Just repeating myself...
The code to get the members that have EXACTLY the given collection of awards:
from Member m
where not exists (
from Award a where a.name in {"Trophy", "Ribbon"}
and a not in(
select * from Award a2 where a2.owner = m
)
) and not exists (
from Award a3 where a3.owner = m and a3 not in {"Trophy", "Ribbon"}
)
You can force distinct results by adding a DISTINCT_ROOT_ENTITY result transformer to the query call, IE:
getSession().createQuery(hql).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
I'm having a similar problem, but what I need to do is (following your example) to select all the members, who posess ALL of the awards and no more. So in your example the only correct result would be Sue. Any ideas?
Following class structure is given:
class Job
{
String description;
Collection<JobHistory> history;
}
class JobHistory
{
Date assignDate;
User jobOwner;
}
class JobOwner
{
String name;
String id;
}
This class-structure is accessible on the db via JPA. In the DAO-Layer I can write queries in JPA syntax.
The Problem: I want a list with Job and JobHistory entries for a given owner with given id and who is the last one in the Jobhistory of the job (ordered by assignDate). Sounds quite complicated, perhaps simpler: give me all jobs and JobHistory where specified owner is the actual owner of the job.
Update: for clarity I will slightly change the names of the classes.
class Job
{
String description;
Collection<JobOwnerHistory> history;
}
class JobOwnerHistory
{
Date assignDate;
User jobOwner;
}
class JobOwner
{
String name;
String id;
}
Every Job has a history of his owners sorted by assignDate. The actual owner got the job last assigned (i.e. MAX(assignDate)). I want find for every job the JobOwnerHistory entry with MAX(assignDate) for a specific user User.
I found the following answer for the query:
SELECT j, h FROM Job j JOIN j.history h JOIN h.jobOwner u
WHERE u.name = :name AND
(SELECT MAX(h2.assignDate) FROM Job j2 JOIN j2.history h2
WHERE h2 member of j.history) = h.assignDate
The most important part in the query is the subselect with MAX(h2.assignDate) because I want to get the job and the newest entry in the owner-history.
Try:
SELECT j, j.history FROM Job j JOIN User u WHERE u.name = :name
If I were to do this in EclipseLink, I would change it slightly:
public List<Job> getAllJobsForUser(String username) {
List<Job> jobs = entityManager
.createQuery("SELECT j FROM Job j JOIN User u WHERE u.name = :name")
.setParameter("name", username)
.setHint(QueryHints.BATCH, "j.history")
.queryForList();
}
The difference? In the first version, you're returning two objects, so you have to retrieve them from a List or Object arrays whereas in the second, the query hint just loads all the job histories from an (assumedly) lazyy one-to-many relationship.
I don't know if Hibernate has an equivalent to this. Toplink Essentials doesn't. But it's one of my favourite features of EclipseLink.
Oh and obviously you can (and probably should) use a named query instead of an adhoc query like I've done (since those can be verified during the build).