Search code examples
javahibernatejpapersist

JAVA JPA - Regular solution to persist all objects in project


I'm working on a backend which creates new user, news, various data etc.

So far I could create and persist a new User in the database. I think there will be many further entities also with relations. At this point I only see two way to persist the data:

  • create CreateXY, UpdateXY and DeleteXY classes
  • or code the persist method in each entity object

I think that is quiet redundant to write the persists again and again. Is there a nice way to go to persist objects in a nice way?

Main.java

package database;

import java.util.logging.Level;
import java.util.logging.Logger;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

import backend.User;

public class Main {
    private static final Logger LOGGER = Logger.getLogger("JPA");

    public static void main(String[] args) {
        Main main = new Main();
        main.run();
    }

    public void run() {
        EntityManagerFactory factory = null;
        EntityManager entityManager = null;
        try {
            System.out.println("START");
            factory = Persistence.createEntityManagerFactory("shareiffUnit");
            System.out.println("END");
            entityManager = factory.createEntityManager();
            persistPerson(entityManager);
        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, e.getMessage(), e);
            e.printStackTrace();
        } finally {
            if (entityManager != null) {
                entityManager.close();
            }
            if (factory != null) {
                factory.close();
            }
        }
    }

    private void persistPerson(EntityManager entityManager) {
        EntityTransaction transaction = entityManager.getTransaction();
        try {
            transaction.begin();
            User person = new User();
            person.setName("Homer");
            person.setPassword("Simpson");
            entityManager.persist(person);
            transaction.commit();
        } catch (Exception e) {
            if (transaction.isActive()) {
                transaction.rollback();
            }
        }
    }

}

User.java

package backend;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table
public class User {

    @Id
    @GeneratedValue
    private int id;
    private String name;
    private String password;
    private Boolean isActive = false;


    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public Boolean isActive() {
        return isActive;
    }
    public void setActive(boolean isActive) {
        this.isActive = isActive;
    }

}

Solution

  • I tend to have a set of manager-like classes along with a base for each manager class. The base is something like:

    public class SomeBaseWritableDAO<T> {
        @PersistenceContext
        private EntityManager entityManager;
    
        protected EntityManager getEntityManager() {
            return entityManager;
        }
    
        public void save(T entity) {
            getEntityManager().persist(entity);
        }
    
        public T update(T entity) {
            return getEntityManager().merge(entity);
        }
    
        public void delete(T entity) {
            getEntityManager().remove(entity);
        }
    }
    

    That takes care of any @Entity type. Then, if I need more than the basic CRUD operations I'll create a class specific manager:

    public class SpecificDAO extends SomeBaseWritableDAO<SpecificEntity> {
    
        public SpecificEntity findBySomeCode(String inviteCode) {
            final String queryString = "select model from SomeEntity model " +
                    "where model.code= :inviteCode";
    
            Query query = getEntityManager().createQuery(queryString);
            query.setParameter("inviteCode", inviteCode);
    
            try {
                return (SomeEntity) (query.getSingleResult());
            }
            catch( NoResultException nre ) {
                return null;
            }
        }
    }
    

    There are other ways to do this but this pattern has worked well in the past. If you've got a properly designed database with referential integrity then a good reverse engineering tool like the one in Eclipse or IntelliJ can generate your one to one and one to many relationships.