I am using org.appfuse.dao.hibernatepackage and I have used all the method in the GenericDaoHibernate<T,PK> class.
I found these methods
public List<T> getAll();
public List<T> getAllDistinct();
public List<T> search(String searchTerm);
public T get(PK id);
public boolean exists(PK id);
public T save(T object);
public void remove(T object);
public void remove(PK id);
public List<T> findByNamedQuery(String queryName, Map<String, Object> queryParams);
public void reindex();
public void reindexAll(boolean async);
I have some model classes, services and methods.
Now I want to get list of object using some other fieled in the model class other than id(I have some common fields in many model classes).
I need to write similar methods in all the services and daos. So i was thinking is it possible to create a common method in generic dao.
The following I tried, but it didn't work.
public T getbyClientKey(Long clientkey) {
Session sess = getSession();
IdentifierLoadAccess byId = sess.byId(persistentClass);
List<T> entity = (List<T>) byId.load(clientkey);
if (entity == null) {
log.warn("Uh oh, '" + this.persistentClass + "' object with client '" + clientkey + "' not found...");
throw new ObjectRetrievalFailureException(this.persistentClass, clientkey);
}
return entity;
}
I knew this will be error. and it showed TypeCastingException, because return type of byId.load(id) is object only, not List.
So how can I create a method like that?
If so, I think I can create method for remove() also(But that's not necessary for me now, may be in future).
The Javadoc for IdentifierLoadAccess is pretty clear in how the load method should behave:
Return the persistent instance with the given identifier, or null if there is no such persistent instance.
This means it should return just one object, not a List of objects. Try casting it to T instead.
If you want to query your entity (that is, retrieve items by any other means than primary key), you most likely want to implement the search(String) method.
If you want to query your entity (that is, retrieve items by any other means than primary key), take a look at the UserDaoHibernate that is shipped with AppFuse. It contains a method loadUserByUsername() which is implemented like this:
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List users = getSession().createCriteria(User.class).add(Restrictions.eq("username", username)).list();
if (users == null || users.isEmpty()) {
throw new UsernameNotFoundException("user '" + username + "' not found...");
} else {
return (UserDetails) users.get(0);
}
}
Obviously, if you want to return all items, it should be modified a bit (this one is made up):
public List<UserDetails> loadLockedUsers() {
List<UserDetails> users = (List<UserDetails>) getSession().createCriteria(User.class).add(Restrictions.eq("account_locked", true)).list();
return users;
}
Related
Currently I am working on Spring Boot + Hibernate and I mostly end up writing repetitive hibernate query every time which are doing same kinda job, only difference is that the entity class different.
Example: here, I am retrieving a list from three different tables improvement_area, development_area and suggested_area. Below are the respective model class.
public List<ImprovementArea> getImprovementAreaList(MainPlanSheet planSheet) {
return HibernateUtils.getSession(sessionFactory)
.createCriteria(ImprovementArea.class).add(Restrictions.eq("planSheet", planSheet))
.list();
}
public List<DevelopmentArea> getDevlopmentAreaList(MainPlanSheet planSheet) {
return HibernateUtils.getSession(sessionFactory)
.createCriteria(DevelopmentArea.class).add(Restrictions.eq("planSheet", planSheet))
.list();
}
public List<SuggestedArea> getSelectedSuggestedGoal(MainPlanSheet planSheet) {
return HibernateUtils.getSession(sessionFactory)
.createCriteria(SuggestedArea.class).add(Restrictions.eq("planSheet", planSheet))
.list();
}
as you could see all the three query is doing the same job, retrieving data from the respective model class.
Can someone please help me or suggest a better approach to make it generic?
Now another query added which accept Integer as parameter:
public List<OnBoardedEmployee> getOnBoardedEmployees(Integer empId) {
return HibernateUtils.getSession(sessionFactory)
.createCriteria(OnBoardedEmployee.class)
.add(Restrictions.eq("emId", empId))
.list();
}
In this scenario how can I make one generic Instead of four different query?
You can simply pass the class as an argument:
public <T> List<T> getDevlopmentByEntity(MainPlanSheet planSheet, Class<T> entity) {
return HibernateUtils.getSession(sessionFactory)
.createCriteria(entity)
.add(Restrictions.eq("planSheet", planSheet))
.list();
}
And invoke it like:
List<DevelopmentArea> developmentAreas = getSelectedSuggestedGoal(planSheet, DevelopmentArea.class);
Edit: the last snippet can be rewritten as:
public <T> List<T> getDevlopmentByEntity(String param, Object value, Class<T> entity) {
return HibernateUtils.getSession(sessionFactory)
.createCriteria(entity)
.add(Restrictions.eq(param, value))
.list();
}
Spring's Security "hasPermission" method has an implementation, which (as I get) is intended for passing class name (targetType) and Object Id (Serializable).
So could you please explain (at least in general) how to do this implementation right?
I've searched for example of passing object ID and found no any (even at Spring's doc).
In my situation I want to check for User's DELETE permission on some of my classes (for instance, "Goal"). All of these classes has universal methods and fields, so I can have universal logic for checking permission inside a PermissionEvaluator.
For doing this I'm intended to pass an Object's ID and Object's class name into PermissionEvaluator and do the check here like this:
#PreAuthorize("hasPermission(#id, 'Goal','DELETE')")
It sounds pretty good till it not comes to the implementation, because I don't really understand how can I get Object's instance by Class name and Id inside Permission evaluator.
#Component
public class CustomPermissionEvaluator implements PermissionEvaluator
#Override
public boolean hasPermission(Authentication authentication, Serializable serializable, String targetType,
Object permission) {
Yes, I can instantiate object by Class.forName(targetType), but how can I get it's instance by Id (serializable) from appropriate Repository then? (I have different repository for every object).
#Autowiring all of my 30 repositories would be the madness.
Implemented my service, which takes Object ID and Object Type and then sends back Object, which I can later unbox. I used dynamic HQL, so no need in 30+ JPA repositories autowiring (my bad, I missed this possibility at the beginning).
#PersistenceContext
EntityManager entityManager;
static String entityClassPath="com.platform.entity.";
public Object getEntity(String className, Long id) {
String classToQuery = capitalize(className);
/* Check if Entity class exists to decide whether to query DB or not */
try {
Class cls = Class.forName(entityClassPath + className);
} catch (Exception e) {
return null;
}
/* Query DB if Entity class exist */
Query query;
try {
query = entityManager.createQuery("SELECT Q FROM " + classToQuery + " Q WHERE Q.id=?1");
query.setParameter(1, id);
return query.getSingleResult();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
Currently I'm having some methods in my DAO layer with multiple select queries. What I was thinking is to have a generic method for all these three methods so that it can be used for further also. Here are my methods.
public List<Customer> findAll(){
String sql = "SELECT * FROM CUSTOMER";
List<Customer> customers = getJdbcTemplate().query(sql,
new BeanPropertyRowMapper(Customer.class));
return customers;
}
For finding phone numbers of a customer.
public List<Phone> findPhoneNumbers(int custId){
String sql = "SELECT * FROM PHONE WHERE CUST_ID="+custId;
List<Phone> phoneNumbers = getJdbcTemplate().query(sql,
new BeanPropertyRowMapper(Phone.class));
return phoneNumbers;
}
and so on.
Can these methods can be converted in a single generic method, so that it can be called from my service layer. Any suggestions or ideas would be greatly appreciated.
You can use a generic method and let the caller specify the class.
It's easy for findAll
public <T> List<T> findAll(Class<T> entityClass, String tableName){
String sql = "SELECT * FROM " + tableName;
return getJdbcTemplate().query(sql,
new BeanPropertyRowMapper(entityClass));
return phoneNumbers;
}
You can further improve this by using class metadata, such as specifying an annotations:
#Target(ElementType.Type)
public #interface MappedTable {
String tableName();
}
//apply the annotation to bean classes:
#MappedTable(tableName="CUSTOMERS")
public class Customer {}
Which will allow your findAll method to look like:
public <T> List<T> findAll(Class<T> entityClass){
String sql = "SELECT * FROM " + entityClass
.getAnnotation(MappedTable.class).tableName();
return getJdbcTemplate().query(sql,
new BeanPropertyRowMapper(entityClass));
return phoneNumbers;
}
Implementing findByXyZ will be trickier, but you can use a similar approach that either takes the full query from the caller or that uses additional annotation-based metadata.
Note that the complexity of this kind of code grows very fast. That's why it's a good idea to consider using ORM tools instead of reinventing them (the above is just an idea for simple cases as the one in the question).
public <T> List<T> findAll(String sql, Class<T> clazz) {
return getJdbcTemplate().query(sql, new BeanPropertyRowMapper(clazz));
}
Then you call
String sql = "SELECT * FROM CUSTOMER";
List<Customer> customers = findAll(sql, Customer.class);
Or
String sql = "SELECT * FROM PHONE WHERE CUST_ID="+custId;
List<Phone> phoneNumbers = findAll(sql, Phone.class);
The problem is that you have to construct sql statement before calling the method.
Maybe you want an android sqldatabase-like interface and construct sql statement in the method.
public <T> List<T> findAll(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, Class<T> clazz) {
String sql = // construct sql statement
return getJdbcTemplate().query(sql, new BeanPropertyRowMapper(clazz));
}
I'm not familiar with sql statement, you may find something in the Android SDK SQLiteQueryBuilder.buildQueryString(...).
If you really want to return a single item not a list with one item, you need another method.
public <T> T findOne(String sql, Class<T> clazz) {
// your sql statement should contains something like "limit 1"
List<T> result = findAll(sql, clazz);
return result.isEmpty() ? null : result.get(0);
}
If you need one method but you require to return List<T> for multiple data and T for single data. Try this:
public <T> Object findAll(String sql, Class<T> clazz, bool one) {
List<T> all = getJdbcTemplate().query(sql, new BeanPropertyRowMapper(clazz));
return one ? all.get(0) : all;
}
But I don't really suggest this approach. I don't think it is necessary to return a single item rather than a list with a single item.
You can use inheritance to achieve this
1) class Customer
2)class PhoneNumber extends Customer
3) class Address extends Customer
4) Declaring methods as
public List<T> findPhoneNumbers(Customer customer){
if(customer instanceOf PhoneNumber) {sql ="get phone number query ...."}
else if(customer instanceOf Address) {sql ="get address query ...."}
else {sql = get customer query}
}
Now in the calling method(ServiceLayer), you can pass appropriate object to choose query and get result
How to use hql update query using hibernate template
thi is the hql statement "update Login set empSmartId = 48750005" +" where empPassword = 6328ef1675ddb7106eba8dc2661961d7"
using getHibernatetemplate()
Current code:
public class LoginDaoImp extends HibernateDaoSupport implements LoginDao {
public boolean resetAttempt(Login login) {
try { login.setAttempt(0);
getHibernateTemplate().update(login);
return true;
} catch (Exception e) { e.printStackTrace(); }
return false; }
i can save whole pojo class above code work but i want to use where condition to update only hibernateTemplate to update the data
you would be looking something like this
public class LoginDaoImp extends HibernateDaoSupport implements LoginDao
{
public boolean resetAttempt(Login login)
{
try
{
// you should create method for login to retrived based on password
//Remember getting login by password is not correct way, Instead you you should use primary key
//Getting persisted object of Login
Login persisted_login = getLoginByPassword(6328ef1675ddb7106eba8dc2661961d7);
//Setting value in persisted object of Login
persisted_login.setEmpSmartId (48750005);
getHibernateTemplate().update(persisted_login);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
I know this question is very old but, may this solution help someone else...
Here is a trick to update a record in DB.
The trick is first fetch the required record from the DB, update the required fields using setter methods of associated POJO class & then give a call to hibernateTemplate.save(Object entity) method, just like below:-
public void updateUser(User user, String password) {
#SuppressWarnings("unchecked")
List<User> results = (List<User>) hibernateTemplate
.find("FROM User where username = ?", new Object[] { new String(user.getUsername()) });
User userToBeUpdate = results.get(0);
userToBeUpdate.setPassword(password);
hibernateTemplate.save(userToBeUpdate);
}
This is working solution in my case.
For work with database, my class extends HibernateDaoSupport class and inside the methods I'm using Spring HibernateTemplate.
So, for delete a row in database I use this method:
public void delete(MyObject obj) {
getHibernateTemplate().delete(obj);
}
all ok!
But, at this moment I'm trying to implement a method that can delete a row based on id:
public void delete(final long id) {
// some code here
}
And I can't find some HibernateTemplate method like this:
getHibernateTemplate().remove(id)
What is a good solution for me in this case?
delete using particular id,
public void delete(long id)
{
Session session ;
MyObject myObject ;
session = sessionFactory.getCurrentSession();
myObject = (MyObject)session.load(MyObject.class,id);
session.delete(myObject);
//This makes the pending delete to be done
session.flush() ;
}
Also consider encapuslate this methods in try/catch/finally and log the error as needed
Another alternative is:
public void deleteById(Class clazz,Integer id) {
String hql = "delete " + clazz.getName() + " where id = :id";
Query q = session.createQuery(hql).setParameter("id", id);
q.executeUpdate();
}
As you mentioned, there s not such method in HibernateTemplate. You can do the following,
hibernateTemplate.delete(hibernateTemplate.get(Class,Id));
You can also use below method:
public void deleteById(Class clazz,Integer id) {
hibernateTemplate.bulkUpdate("delete from "+clazz.getName()+" where id="+id);
}
There is a simple solution by creating an object and setting only the ID:
Product product = new Product();
product.setId(37);
session.delete(product);
The drawback of this simple solution is that it doesn’t remove the associated instances.
If you have some attribute (another entity related) of the product to be deleted, you will need to load the product before.
Serializable id = new Long(17);
Object persistentInstance = session.load(Product.class, id);
if (persistentInstance != null)
{
session.delete(persistentInstance);
}
This will issue (if you have an attribute table in cascade) a delete on the children attributes.