1

I have a User Entity class which maps a User table in a MySQL DB. This was auto-generated using the Hibernate Tools in Eclipse.

Then, I wrote a generic DAO interface:

package dal.genericdao;
public interface GenericDAO <EntityClass, IDClass> {

    EntityClass create(EntityClass entity);

    void delete(IDClass id);

    EntityClass findById(IDClass id);

    EntityClass update(EntityClass entity);   
}

which is implemented in a GenericDAOImpl class which uses EntityManager for CRUD operations. Here is a snippet of it

package dal.genericdao;

import javax.persistence.PersistenceContext;

public class GenericDAOImpl<EntityClass, IDClass> implements GenericDAO<EntityClass, IDClass> {

    @PersistenceContext private EntityManager entityManager;


// ---- In the original post I omitted this piece of code for shortness. It only retrieves the runtime EntityClass ----
    private Class<EntityClass> entityClass;

    @SuppressWarnings("unchecked")
    public GenericDAOImpl() {
        entityClass = (Class<EntityClass>) ((ParameterizedType) getClass().getGenericSuperclass())
                        .getActualTypeArguments()[0];
    }

// --------------

    @Override
    public EntityClass create(EntityClass entity)
    {
        entityManager.getTransaction().begin();
        entityManager.persist(entity);
        entityManager.flush();
        entityManager.getTransaction().commit();

        return entity;
    }


    @Override
    public void delete(IDClass id)
    {
        ...
    }

    @Override
    public EntityClass findById(IDClass id)
    {
        ...
    }

    @Override
    public EntityClass update(EntityClass entity)
    {
        ...
    }


}

So the UserDAO is this

import dal.genericdao.GenericDAOImpl;
import dal.User;
import javax.enterprise.inject.Default;

@Default
public class UserDAO extends GenericDAOImpl<User, String> {
}

If I run some tests on the UserDAO class everything works as expected.

The problem shows off when I try to persist (by mean of the UserDAO.create() method) an Entity which already exists in the DB. In fact, the entityManager.persist(entity) method doesn't warn me whether I'm persisting an existent entity (which should, theoretically, provoke a primary key constraint violation) or not.

Moreover, in the entityManager.persist(entity) method I cannot access the Entity identifier value because it is "hidden" with the generic IDClass class (so I cannot run GenericDAOImpl.findById(IDClass) to verify the presence of the Entity prior to the persist operation).

What do you think about this problem? How would you solve this?

Thank you

gvdm
  • 3,006
  • 5
  • 35
  • 73

2 Answers2

0

Consider using the Spring framework. The Spring-Data-JPA project has excellent Repository implementations. Among other features they remove the burden to check for existing entities.

achingfingers
  • 1,827
  • 5
  • 24
  • 48
  • Hi @achingfingers, thanks for the reply. In the past I've used Spring-Data-JPA and loved the Repository system. This time I cannot use Spring Framework because of other components of the application (external to the DAL but in the same CDI context) which must run in the Java EE CDI. – gvdm Jun 11 '14 at 15:14
0

Consider to have unique field other than ID in User table and make a check before persist on that field. For instance it can be username or combination of a few fields.

Al1en313
  • 151
  • 6
  • In `User` entity case, the primary key (id) is already the username field. The problem is that in the GenericDAOImpl class I cannot access the value of the primary keys because they are "masqueraded" by the IDClass class (which is String in case of User entity, but can be Integer or any other class type in other cases) – gvdm Jun 11 '14 at 15:35
  • So where is the problem? Just use entityManager.find(className, id). Also this QA can be useful for your case http://stackoverflow.com/questions/3437897/how-to-get-class-instance-of-generics-type-t – Al1en313 Jun 11 '14 at 15:47
  • Indeed that is the way I perform the `GenericDAOImpl.findById(IDClass id)` operation (the ID value is passed through parameters). On the other hand, in the `GenericDAOImpl.create(EntityClass entity)` method I have no reference to the particular Entity instance and its id value. So, for example, in the `GenericDAOImpl.create(EntityClass entity)` method I have no mean to know at compile time the entity's class (which can be user or anythig else) so I cannot access User.username (or whichever the Entity's identifier is). – gvdm Jun 11 '14 at 15:58
  • I edited the original post adding the code which retrieves the runtime `EntityClass`. This is used in the `findById` method which passes it to the EntityManager.find() method. What I cannot do is retrieve the IDClass' value (only its class type) – gvdm Jun 11 '14 at 16:12
  • If I'm not mistaken you can perform check outside of your DAO classes using consequently findById and persist. Other option is to write helper method which will perform this operation inside DAO(passing both parameters EntityClass, IdClass) – Al1en313 Jun 11 '14 at 16:20
  • The second option you mentioned is the one I thought of, but this means that the `GenericDAO.create(EntityClass entity)` method will be written this way: `GenericDAO.create(EntityClass entity, IDClass id)`. Whoever sees this method from the outside of the UserDAO class would think "Why I have to pass the User's ID while I'm passing the entire User object too?" – gvdm Jun 11 '14 at 18:52
  • Yep, it's ugly. I was thinking about common interface which each entity will implement with method getId(). In genericDAO extends EntityInterface, IDClass>. – Al1en313 Jun 11 '14 at 20:23
  • I see only one problem with this (surely good) solution: my Entities are generated automatically with Hibernate Tools in Eclipse, so I cannot tell Hibernate to make the generated Entities inherit from the EntityInterface interface. – gvdm Jun 12 '14 at 07:45