2

So I have a sample code like this:

package biz.tugay.books10Aug.dao;
/* User: koray@tugay.biz Date: 10/08/15 Time: 22:54 */

import biz.tugay.books10Aug.model.Book;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

public class BookDaoImpl implements BookDao {

    private EntityManager entityManager;

    public BookDaoImpl(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public void persist(Book book) {
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        entityManager.persist(book);
        transaction.commit();
    }

}

and this is how I unit test it:

package biz.tugay.books10Aug.dao;
/* User: koray@tugay.biz Date: 10/08/15 Time: 22:56 */

import biz.tugay.books10Aug.model.Book;
import org.junit.Test;

import javax.persistence.EntityManager;
import java.text.SimpleDateFormat;
import java.util.Calendar;

public class BookDaoImplTest {

    @Test
    public void testPersistNewBook() throws Exception {
        PersistenceUtil.initalizeEntityManagerFactory();
        EntityManager entityManager = PersistenceUtil.getEntityManager();
        BookDao bookDao = new BookDaoImpl(entityManager);
        String isbn = new SimpleDateFormat("HHmmss").format(Calendar.getInstance().getTime());
        Book book = new Book();
        book.setIsbn(isbn);
        book.setName("Just Another Book in the DB, Volume: " + isbn);
        book.setPrice(10);
        book.setPublishDate(Calendar.getInstance().getTime());
        book.setPublisher("002");
        bookDao.persist(book);
    }

}

This all works fine. My question is about OOP.

I decided that BookDaoImpl should not be responsible for getting the EntityManager. It should be the BookService 's responsibility. Why? I a do not know really.

Also, whos responsibility should be to get transaction, begin and commit? Again BookService or BookDao?

Koray Tugay
  • 22,894
  • 45
  • 188
  • 319

2 Answers2

1

JPA Transaction should be managed on a service layer. Here's an counterexample: consider you have a find method in your DAO layer:

public Book find(long id) {
      return entityManager.find(Book.class, id);
}

And your Book class owns a collection of pages:

@OneToMany(mappedBy = "book", fetch = LAZY")
private Set<Page> pages;

public Set<Page> getPages() {
    return pages;
}

If the entityManager has a lifecycle within a DAO, the call of getPages() method made from your service layer will result in lazy initialization exception

Of course in each rule there are exceptions, but in general you should manage your transaction on service layer (or repository layer depending on wording). You can even use MANDATORY transaction demarcation attribute in your DAO layer in order to make it mandatory.

bedrin
  • 4,458
  • 32
  • 53
  • So my persist method should only be entityManager.persist(book);? Do I understand right? – Koray Tugay Aug 10 '15 at 20:40
  • @KorayTugay correct; Usually you use JPA together with some App Container or Spring which manage transactions for you. And in this case the EntityManager is bounded to transaction, i.e. transaction is started in Service Layer - at this point of time entity manager is created, bounded to transaction and propagated to DAO layer – bedrin Aug 10 '15 at 20:45
  • Thanks, I am just trying to learn so I am not using any container currently. One last question, should I pass an entity manager in the constructor or per each method? – Koray Tugay Aug 10 '15 at 21:02
  • @KorayTugay this is a great approach for learning! Frameworks like Spring pass it via a proxy which takes the actual entity manager from thread local variable. It allows you to have a single instance of DAO class on one hand and do not add it to parameters of each method on the other. For learning purposes you can choose any approach actually - they both will work. Using constructor means that you have to create a new DAO instace for each service method call; passing it via parameters means that you'll make the API more difficult. When you feel yourself comfortable with JPA try it with Spring! – bedrin Aug 10 '15 at 21:09
  • Thanks a lot for your time. If you have time, could you check http://codereview.stackexchange.com/questions/100529/is-the-seperation-of-concerns-and-injections-ok-here as well? Thanks a lot again, regards. – Koray Tugay Aug 10 '15 at 21:54
1

my opinion is it's ok that BookDao knows about EntityManager since it's about way of data persistence. Regarding transaction - it's responsibility of service layer since it;s responsible for business logic implementation and transaction borders defines in business requirements. However it would be great to implement transaction management independently from persistence technology (now you are using JPA, tomorrow JDBC, later something else). Think Spring's transactions annotations could be a good example of this approach.

Stan
  • 1,410
  • 10
  • 14
  • So I should not provide the EntityManager in constructor but rather obtain it in the methods of DAO? But then how will I start transaction in the Service layer? – Koray Tugay Aug 10 '15 at 20:38
  • For example your DAO level may provide methods for start/commit transaction. In this case you will be abstracted from implementation of your persistence level. – Stan Aug 10 '15 at 20:48