I have a Spring-boot project, in my project I defined two EntityManager - for two different DB.
All of my entities (tables) are common for the two different DB.
The only thing that is different is the Dao layer - but because some of my db queries are shared I decided to create - a common Dao abstract layer. and i added a getEntityManager() function to the class that extend the abstract class.
Example:
#Repository
#Transactional(value = "secondaryTransactionManager")
#javax.transaction.Transactional
public class TasksSecondaryDao extends TasksDaoAbstract {
#PersistenceContext(unitName = "secondary")
private EntityManager entityManager;
#Override
public EntityManager getEntityManager() {
return entityManager;
}
public void updateTask(Task task) {
entityManager.merge(task);
}
}
#Repository
#Transactional
public class TasksFirstDao extends TasksDaoAbstract {
#PersistenceContext
private EntityManager entityManager;
#Override
public EntityManager getEntityManager() {
return entityManager;
}
public void updateTask(Task task) { entityManager.merge(task); }
}
public abstract class TasksDaoAbstract {
#Transactional(Transactional.TxType.NEVER)
public List<Task> getAll() {
return getEntityManager().createQuery("FROM Task",
Task.class).getResultList();
}
public abstract EntityManager getEntityManager();
}
In general this code is working. But if I am trying to put updateTask method in the abstract class (with #Transactional) it look like the code is working (no error) but the DB is not updating.
I can not understand why the query is not working from the abstract class, the query that only getting data from the db is working from the abstract class.
Related
I am on Weblogic 12c + JPA/Hibernate + EJB 3.
I wish to simplify my class model as follow:
public abstract class AbstractEJBBean {
#PersistenceContext(unitName = "myPU")
private EntityManager entityManager;
}
#Local
public interface FirstEJB {
void someMethod1();
}
#Stateless
public class FirstEJBImpl extends AbstractEJBBean implements FirstEJB {
#Override
public void someMethod1() {
// Here entityManager has been injected.
}
}
#Local
public interface SecondEJB {
void someMethod2();
}
#Stateless
public class SecondEJBImpl extends AbstractEJBBean implements SecondEJB {
#Override
public void someMethod2() {
// Here entityManager has NOT been injected!!!
}
}
In such situation, Weblogic starts (no errors logged), the application starts, but: only then entity manager into FirstEJBImpl instance have been injected. The one inside SecondEJBImpl is null!!!
I never seen any like this.
Could somebody tell my why and how to avoid it?
Thank you so much!!!
I found the solution on my own.
I suppose it is a Weblogic bug, but I am not so sure, but my solution works as expected.
I had to remove the abstract base class and inject the entity manager directly inside each EJB.
#Local
public interface FirstEJB {
void someMethod1();
}
#Stateless
public class FirstEJBImpl implements FirstEJB {
#PersistenceContext(unitName = "myPU")
private EntityManager entityManager;
#Override
public void someMethod1() {
// Here entityManager has been injected.
}
}
#Local
public interface SecondEJB {
void someMethod2();
}
#Stateless
public class SecondEJBImpl implements SecondEJB {
#PersistenceContext(unitName = "myPU")
private EntityManager entityManager;
#Override
public void someMethod2() {
// Here entityManager has been injected too! :)
}
}
I'm trying to follow code reusing best practices.
I have generic DAO interface with some common methods:
public interface DaoInterface<T> {
T findById(int id);
//...more methods...
}
and its implementation class:
public class GenericDao<T> implements DaoInterface<T> {
#SuppressWarnings("unchecked")
private final Class<T> persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
#Autowired
protected SessionFactory sessionFactory;
#Override
#SuppressWarnings("unchecked")
public T findById(int id) {
Session session = sessionFactory.getCurrentSession();
return (T) session.get(persistentClass, id);
}
//...more methods...
}
Then my every concrete implementation class extends GenericDao and implements its interface.
I also have Service layer in my application. Some Services' methods completely delegate their work to DAO classes. So in the each concrete Service implementation I autowire appropriate DAO class and call its methods.
So now it looks:
public interface CustomerService {
Customer findById(int id);
}
and implementation:
#Service
#Transactional(readOnly = true, rollbackFor = Exception.class)
public class CustomerServiceImpl implements CustomerService {
#Autowired
private CustomerDao customerDao;
#Override
public Customer findById(int id) {
return customerDao.findById(id);
}
}
My question is - how to generify Service classes in the same way as DAO? So that my concrete class will look:
public class CustomerServiceImpl extends GenericService<Customer> implements CustomerService {
.....
}
The problem is that I cannot autowire DAO class in Generic Service:
#Autowired
private GenericDao<T> dao;
so that I could call dao's methods.
Should I do it in the constructor?
And one more question - where is the right place to annotate methods with #Transactional - in generic class or in every implementation class?
You have to create an instance of a generic Dao and put in the service layer some decision:
#Repository
public class GenericDao implements DaoInterface<T> {
//The type must be aquired at runtime,otherwise it may not be thread safe
#Autowired
protected SessionFactory sessionFactory;
#Override
#SuppressWarnings("unchecked")
public T findById(int id,Class<?> persistenceClass) {
Session session = sessionFactory.getCurrentSession();
return (T) session.get(persistenceClass, id);
}
//...more methods...
}
Also if you need a good generic repository layer take a look for Spring Data Jpa
This will make one and only one instance of the GenericDao.
Next you have 2 choice:
Create a singleton services for all your needs
Create a class service for every entity
abstract class GenericService<T> {
#Autowired
protected GenericDao dao;
#SuppressWarnings("unchecked")
protected final Class<T> persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
#Override
public T findById(int id) {
return dao.findById(id,persistenceClass);
}
}
Now every one of your service must extends the GenericService with a supplied persistence type and the job is done.
I created a spring application where i decided to add a BaseDAO to eliminate redundant create,
update,delete,findByid,and findAll methods for every dao. So i created a baseDao and every dao should extend this BaseDAO.
BaseDaoImpl
public class BaseDAOImpl implements BaseDAO{
SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf){
this.sessionFactory = sf;
}
#Override
public void create(ModelBase modelBase) {
Session session = this.sessionFactory.getCurrentSession();
session.persist(modelBase);
}
#Override
public void update(ModelBase modelBase) {
Session session = this.sessionFactory.getCurrentSession();
session.update(modelBase);
}
#Override
public Collection findAll(Class aClass) {
Session session = this.sessionFactory.getCurrentSession();
Collection modelCols = session.createQuery("from "+aClass.getSimpleName()).list();
return modelCols;
}
#Override
public ModelBase findById(Class aClass, Integer id) {
Session session = this.sessionFactory.getCurrentSession();
ModelBase modelBase = (ModelBase) session.load(aClass, new Integer(id));
return modelBase;
}
}
Then i extends this Dao to each DAO
EmployeeDAOImp
public class EmployeeDAOImpl extends BaseDAOImpl implements EmployeeDAO{
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf){
this.sessionFactory = sf;
}
}
I created a BaseService like this. But when i try to access BaseDAO methods from EmployeeDAO it returns null pointer exception.
Why this happen. I dont want to use genericDAO from google. Because we should create DAOs
for each model. I want to eliminate this. So I follow this method.
Have you though about Spring Data project & Spring Data JPA in particular?
This would save you lots of time, since you would no longer need to write your DAO / Repositories from scratch, all you need to do is enable Spring Data JPA, and add needed interfaces. It should save you tons of time.
http://projects.spring.io/spring-data-jpa/
http://spring.io/guides/gs/accessing-data-jpa/ - Sample project
Your are overriding setSessionFactory from base class for no reason, its already available with extending class EmployeeDAOImpl , either remove it or try below:
public class EmployeeDAOImpl extends BaseDAOImpl implements EmployeeDAO{
//this reference should be from base class,
// the extending class ref is hiding base ref.
// private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf){
super.setSessionFactory(sf);
}
}
Something like the following should work (note the use of constructor rather than setter injection). In the BaseDAO:
public class BaseDAOImpl implements BaseDAO {
private final SessionFactory sessionFactory;
public BaseDAOImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
Then in the Employee DAO:
public class EmployeeDAOImpl extends BaseDAOImpl implements EmployeeDAO {
#Inject
public EmployeeDAOImpl (SessionFactory sessionFactory) {
super(sessionFactory);
}
}
You can create generic dao.
#Repository("genericDao")
public class GenericDaoImpl<T,PK extends Serializable> implements GenericDao<T, PK> {
protected Class<T> entityClass;
public T create(T t) {
this.entityManager.persist(t);
return t;
}
public T read(PK id,Class<T> c) {
return (T)this.entityManager.find(c, id);
}
public T update(T t) {
return this.entityManager.merge(t);
}
public void delete(T t) {
t = this.entityManager.merge(t);
this.entityManager.remove(t);
}
public List<T> getAll(Class<T> c){
return this.entityManager.createQuery("SELECT o FROM "+ c.getName() +" o").getResultList();
}
}
UPDATED
You can use as following, TimeRange is a pojo class in the following example. If you do not want a service layer. You can use timeRangeDao in controller.
#Service("timeRangeService")
public class TimeRangeServiceImpl implements TimeRangeService{
#Autowired
GenericDao<TimeRange,Long> timeRangeDao;
public List<TimeRange> getAllTimeRanges(){
return timeRangeDao.getAll(TimeRange.class);
}
#Transactional
public void createTimeRange(TimeRange c) {
timeRangeDao.create(c);
}
#Transactional
public void update(TimeRange p) {
timeRangeDao.update(p);
}
#Transactional
public TimeRange getTimeRange(long id) {
return timeRangeDao.read(id, TimeRange.class);
}
#Transactional
public void delete(long id) {
TimeRange timeRange = new TimeRange();
timeRange.setId(id);
timeRangeDao.delete(timeRange);
}
}
I am writing a CDI-JPA DAO pattern that not using EJB because I am using Tomcat.
Here is my code:
#ApplicationScoped
public class UserDao {
#PersistenceContext(unitName = "unitName1")
EntityManager entityManager;
public void saveUser(User user) {
this.entityManager.persist(user);
}
public void removeUser(User user) {
this.entityManager.remove(user);
}
public void getUser(int id) {
this.entityManager.find(User.class, id);
}
}
Since all my DAO classes are annotated with #ApplicationScoped so I was wondering whether IT IS SAFE to inject entityManager using #PersistenceContext as I did? Can someone tell me is that ok? If NOT, please give me your ideas.
I have a generic DAO class that looks like this:
public class GenericDaoJpa <T extends DomainObject> implements GenericDao<T> {
private final Class<T> type;
#PersistenceContext(type=PersistenceContextType.TRANSACTION, unitName="myPersistenceUnit")
protected EntityManager entityManager;
public GenericDaoJpa(Class<T> type) {
super();
this.type = type;
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public T get(Object id) {
return (T) entityManager.find(type, id);
}
}
The implementation DAO class looks like this:
#Repository("appDao")
public class ProductDaoJpa extends GenericDaoJpa<Product> implements ProductDao{
public ProductDaoJpa() {
super(Product.class);
}
public List<Product> getAllProducts() {
return getAll();
}
}
I have configured another persistentUnit called mySecondPersistenceUnit for a different database. I would like to create a new DAO class that will also extend the GenericDaoJpa class but use a different persistent unit. How can i extend the GenericDaoJpa class but use a different persisitent unit for each DAO?
I tried moving this declaration to each of the DAO classes but this causes the parent class not to compile because it has no reference to the entityManager.
#PersistenceContext(type=PersistenceContextType.TRANSACTION, unitName="myPersistenceUnit")
protected EntityManager entityManager;
Try to use method injection instead:
public class GenericDaoJpa <T extends DomainObject> implements GenericDao<T> {
#PersistenceContext(type=PersistenceContextType.TRANSACTION, unitName="myPersistenceUnit")
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
While child class that need use different PU:
#Repository("appDao")
public class ProductDaoJpa extends GenericDaoJpa<Product> implements ProductDao{
#Override
#PersistenceContext(type=PersistenceContextType.TRANSACTION, unitName="mySecondPersistenceUnit")
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}