The task is to retrieve data from the database for certain list of columns and return as custom already existing class.
I tried to resolve this task with following code:
public List<EntityOne> getServiceProviders(EntityTwo EntityTwo) {
Criteria criteria = createCriteria(EntityOne.class);
criteria.add(Restrictions.eq("EntityTwo", EntityTwo));
criteria.createAlias("spid", "two");
criteria.addOrder(Order.asc("two.entityName"));
criteria.setProjection(Projections.projectionList()
.add(Projections.property("entityId"), "entityId")
.add(Projections.property("publishStatus"), "publishStatus")
.add(Projections.property("two.entityName"), "two.entityName")
.add(Projections.property("two.entityId"), "two.entityId")
);
return criteria.list();
}
But I receive a list of data that is not grouped in class as I wanted.
Your question is not very clear especially where you are attempting to use Restrictions.eq("EntityTwo", EntityTwo) as this will not give proper results. Hibernate however provides a means to return EntityOne as an Object from the Columns selected using Hibernate Transformers class. In your case, you will need to write a custom class with getter setter of the columns you are returning. Note that is is important that the variables be named exactly like the alias columns.
Since your example is not clear, let me illustrate with a simple example: Say I need all purchase OrderAmount grouped by OrderDate and OrderNumber
public static List<YourCustomEntity> getAggregateOrders(){
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = null;
List<YourCustomEntity> list = new ArrayList<YourCustomEntity>();
try {
tx = session.beginTransaction();
Criteria cr = session.createCriteria(PurchaseOrders.class);
cr.setProjection(Projections.projectionList()
.add(Projections.sum("orderAmount").as("sumOrderAmount"))
.add(Projections.groupProperty("orderNumber").as("agOrderNumber"))
.add(Projections.groupProperty("orderDate").as("agOrderDate")));
cr.setResultTransformer(Transformers.aliasToBean(YourCustomEntity.class));
list = (List<YourCustomEntity>) cr.list();
}catch (Exception asd) {
System.out.println(asd.getMessage());
if (tx != null) {
tx.rollback();
}
} finally {
session.close();
}
return list;
}
In this regard, you will need your customEntity to have the three columns returned above. For example:
public class YourCustomEntity {
private double sumOrderAmount;
private String agOrderNumber;
private Date agOrderDate;
//And then the getters and setters
NB: Notice the naming of the variables is the same as the column aliases.
You should use Projections.groupProperty(propertyName);
criteria.setProjection(Projections.groupProperty("propertyName"));
Related
I have an object "Chemical" that is updated according to entries in an HTML page. The data is returned to the Java code correctly, yet this one field is not updating or being created in the database. The chemical entity is defined as follows:
#Entity
#NamedQuery(name="Chemical.findAll", query="SELECT c FROM Chemical c")
public class Chemical implements Serializable {
#Id
#Column(name="chemical_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int chemicalId;
...
private string formula; <--- THE FIELD THAT WILL NOT UPDATE/BE CREATED
....
public void setFormula(String formula) {
this.formula = formula;
}
public String getFormula() {
return this.formula;
}
.....
The Java code that actually saves/updates the database:
public void saveOrUpdate(final T data) throws CPDPersistenceException {
final EntityManager em = getEntityManager();
try {
final EntityTransaction transaction = em.getTransaction();
transaction.begin();
em.merge(data);
transaction.commit();
} catch (final PersistenceException e) {
throw new PersistenceException(e);
}
}
After the code is executed, other fields have changed in the database if changes have been made. However, "formula" is not changed and remains a NULL field. Can anybody see why?
There is I think a difference between UPDATE and CREATE.
Try to replace em.merge(data) with em.persist(data)
Does it save the content the first time you create a new row with persist ?
What is the length of your string definition in the database ?
Check the database logs whenever the HQL is run from your code, do the log complain at one point during the persist ?
It might be necessary to first test if the row exists before you can run a merge.
I am working on a project where using JPA and the following code I am able to retrieve from DB a list of objects which consist the profile of a user. Each object is a two field object (word, frequency)
public class JpaUserprofilesDao implements UserProfilesDao {
#PersistenceUnit
private EntityManagerFactory emf;
EntityManager em;
public EntityManager getEntityManager() {
return emf.createEntityManager();
}
#Transactional
#Override
public List<Object[]> getUserProfiles(Long userId){
em = getEntityManager();
try {
List<Object[]> up =em.createQuery("SELECT up.userprofilesPK.word, up.userprofilesPK.frequency from Userprofiles up WHERE up.userprofilesPK.userid= :userid").setParameter("userid", userId).getResultList();
return up;
} finally {
em.close();
}
}
}
In another class of my project I am using the following block of code in order to put the above information in a Map and be able to manipulate it.
profileObject = peristanceservice.getUserProfiles(userId);
for(Object[] s: profileObject ){
if(!tempList.contains(s[0].toString())){
bag.put( (String) s[0].toString(), Integer.parseInt(s[1].toString()) );
tempList.add(s[0].toString());
}
}
Even though I am getting the result it takes so long time to process the list of objects returned by the persistance service and putting them to the Map, that finally prove useless.
Is there a way to get the Map directly from the persistance service?
Thank you in advance.
this is not exactly what you want, but you can use it.
You can transform List to Map using Guava
Use Maps.uniqueIndex:
Returns an immutable map for which the Map.values() are the given elements in the given order, and each key is the product of invoking a supplied function on its corresponding value.
Example:
Map<String,String> mappedRoles = Maps.uniqueIndex(yourList, new Function<String,String>() {
public String apply(String from) {
// do stuff here
return result;
}});
Well that's really embarrassing I have made a standard pojo class and its dao class for data retrieval purpose. I am having a difficulty to understand a basic procedure to how to handle a customized query data to Pojo class.
let's say my User class is
public class User{
private int userId;
private String username;
private int addressId;
}
public class Address{
private int addressId;
private String zip;
}
public class UserDAO{
public void getUserDetails(){
String getSql = select u.userId, u.username, a.zipcode from user u, address a where u.addressId = a.addressId;
//no pojo class is now specific to the resultset returned. so we can't map result to pojo object
}
}
now how I should model this with my pojo class as if using String to manage this then concept of object oriented vanishes, also complexity would increase in the future as well. kindly guide!
Update for Further Explanation
We know that we can map same table objects with same pojo class, but when the query is customized and there is a data returned which doesn't map to any specific class then what would be the procedure? i.e. should we make another class? or should we throw that data in a String variable? kindly give some example as well.
For this purpose you can use one of implementation of JPA. But as you want to do it manually I will give you small example.
UPD:
public class User {
private int userId;
private String username;
private Address address; // USE POJO not ID
}
public class Address{
private int addressId;
private String zip;
List<User> users;
}
public User getUserById(Connection con, long userId) {
PreparedStatement stmt;
String query = "select u.user_id, u.user_name, a.id, a.zip from user u, address a where a.address_id = u.id and u.id = ?";
User user = new User();
Address address = new Address;
try {
stmt = con.prepareStatement(query);
stmt.setLong(1, userId);
ResultSet rs = stmt.executeQuery();
address.setId(rs.getInt("id"));
address.setZip(rs.getString("zip");
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("user_name"));
user.setAddressId(rs.getInt("address_id"));
user.setAddress(address); // look here
} catch (SQLException e) {
if (con != null) {
try {
System.err.print("Transaction is being rolled back");
con.rollback();
} catch (SQLException excep) {
}
}
} finally {
if (stmt != null) {
stmt.close();
}
}
return user;
}
You shouldn't do new POJO for that query, you should write normal query. And remember - your object model is main, tables in DB is just a way to save data of your application.
We know that we can map same table objects with same pojo class, but when the query is customized and there is a data returned which doesn't map to any specific class then what would be the procedure? i.e. should we make another class?
JPA dynamic instantiation allows you to define a query with a POJO whose constructor specifies only the fields and types you want from the database.
This will perform a JPA selection which will return a List.
If you need to change the query later and the columns are unchanged, your POJO will still work.
If you change the columns, then also change the POJO accordingly.
NOTE:
You must specify fully qualified package and constructor arguments.
Type User must be a JPA-mapped or JPA-annotated entity class.
The entityManager is in JPA EntityManagerFactory.
TypedQuery<User> q;
String sql = "select new com.stuff.User(
int u.userId, String u.username, String a.zipcode)
from User u, Address a where u.addressId = a.addressId";
List<User> list = entityManager.createQuery(sql).getResultList();
for(User u : list) {
doStuff(u);
}
Dynamic instantiation is also handy when you want to select specified columns, but avoid those columns with large data, such as BLOB types.
For example, maybe you want a list of proxy POJO's which represent the fully populated thing, but are themselves not fully populated.
You present the proxy list, and when the user selects one, then you do another query to get the fully populated object.
Your mileage may vary.
There's many ORM frameworks that can do this including Hibernate, myBatis, JPA and spring-JDBC
spring-jdbc and myBatis give you granular control over the SQL whereas with JPA and Hibernate you are usually abstracted away from the SQL.
I suggest you do some reading and figure out which one you like before rolling your own solution.
Your question:
We know that we can map same table objects with same pojo class,
but when the query is customized and there is a data returned
which doesn't map to any specific class then what would be the procedure?
If you have 100 kinds of SQL which returns different combination of columns, could it be to create 100 different POJOs? The answer is "NO, stop using POJO".
This library qood is designed to solve this problem, you can try it.
In Hibernate, is there a way to create an add an Alias to a Criterion object. I have the following to work with:
I have a dynamic search from big Database with many tables. The search has many (25+) optional non-exclusive parameters selected clien-side. This requires the use of the Hibernate Criteria API for managability. In my DAO I have the following method:
Public List<myPojoClass> getDataByCriterion( List<Criterion> restrictionList) {
Session s = HibernateUtil.currentSession();
Criteria c = s.createCriteria(myPojo.class);
for (Criterion crit : restrictionList){
c.add(crit);
}
List<myPojoClass> response = c.list();
return response;
}
I need to do a Join with myOtherPojo.class and would like to know if it is possible to add an alias to the Criteria list above.
Somthing like :
restrictionsList.add(... ...createAlias("myOtherPojo.class" , "mop");
then, I need o add other Logical and to this class as above.
You again! ;)
You could pass a collection of entries (like a HashMap<String, String>) and iterate over them to populate your aliases... like this:
Public List<myPojoClass> getDataByCriterion( List<Criterion> restrictionList, HashMap<String,String> aliases) {
Session s = HibernateUtil.currentSession();
Criteria c = s.createCriteria(myPojo.class);
for (Criterion crit : restrictionList){
c.add(crit);
}
for (Entry<String, String> entry : aliases.entrySet()){
c.createAlias(entry.getKey(), entry.getValue());
}
List<myPojoClass> response = c.list();
return response;
}
You could do something similar if you want to change the fetch modes. Of course the calling method needs to know the data model so it can set up the aliases properly, otherwise you can get errors at runtime.
from what I know there is now way to create joins without instance of Criteria. I suggest you create some wrapper for criteria which would contain criteria and alias definition if necessary and then use Criteria as visitor (like from this Pattern)
interface CriterionWrapper {
void visit(Criteria c);
}
class OnlyCriterionWrapper implements CriterionWrapper {
private Criterion c;
public void visit(Criteria c){c.add(c);}
}
class CriterionWrapper implements CriterionWrapper{
private Criterion c;
private String whateverIsNeededToCreateAlias
public void visit(Criteria c){
c.createAlias(whateverIsNeededToCreateAlias);
c.add(c);
}
}
and then pass List as parameter to your getDataByCriterion() method
Is there any way to obtain Object array of Java Bean fields? I have some bean classes that represent database tables (Hibernate) and I need to retrieve from them Object arrays for jtable model, but it seems that the only way to do this is by calling getXXX methods for each field of each class - a lot of work to do.
If you want a generic way to extract values from a bean, you should look at introspection (package "java.lang.reflect").
Here is a basic example:
Field[] fields = ABeanClass.getDeclaredFields();
Object[] values = new Object[fields.length];
int i = 0;
for (Field field : fields) {
values[i] = field.get(beanInstance);
i++;
}
The way i do it is use a "controller" class which handles all the communication between the model and the database.
You make List of the "objects" like for example private List myList = null;
Now, write a generic method in the controller class. say getList which returns the list. You pass the relative class to the method and it returns you the list using the hibernate session. In your bean, do this
myList = myController.getList(YourBean.class);
And this should be your getlist method.
public List getList(Class c) throws BaseExceptionHandler {
Session session = null;
Transaction tx = null;
String query = null;
List list = null;
try {
query = getStringQuery(c);
if (query != null) {
session = sessFactory.openSession();
tx = session.beginTransaction();
list = (List) session.createQuery(query).list();
tx.commit();
}
} finally {
if (session != null) {
session.close();
}
}
return list;
}
CHEERS :)