7

I am writing an application that's sole purpose in life is to do CRUD operations for maintaining records in database. There are relationships between some of the tables/entities. Most examples I've seen for creating session beans deals with complex business logic/operations that interact with many entities which I don't have.

Since my application is so very basic, what would be the best design for the session bean(s)?

I was thinking of having one session bean per entity which had CRUD the methods defined. Then I thought of combining all of those session beans into a single session bean. And then I found this blog entry which is intriguing, but I must admit I don't understand all of it (what is a ServiceFacade?).

I'm leaning towards session bean/entity class, but would like to hear more experienced opinions.

Thanks.


Oops, here's the blog link: http://www.adam-bien.com/roller/abien/entry/generic_crud_service_aka_dao

sdoca
  • 7,832
  • 23
  • 70
  • 127

1 Answers1

11

Not sure what blog entry you're talking about :) But in your particular situation1, I'd probably use a single session bean implementing an interface similar to:

public interface GenericCrudService {
    public <T> T create(T t);
    public <T> T find(Class<T> type, Object id);
    public <T> void delete(T t);
    public <T> T update(T t);
    public List findWithNamedQuery(String queryName);
    public List findWithNamedQuery(String queryName, int resultLimit);
    public List findWithNamedQuery(String namedQueryName, 
                                   Map<String, Object> parameters);
    public List findWithNamedQuery(String namedQueryName, 
                                   Map<String, Object> parameters,
                                   int resultLimit);
    public <T> List<T> findWithNativeQuery(String sql, Class<T> type);
}

And the bean would be as follow:

@Stateless
@Remote(GenericCrudService.class)
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class GenericCrudServiceBean implements GenericCrudService {
    @PersistenceContext
    private EntityManager em;

    @Override
    public <T> T create(T t) {
        em.persist(t);
        return t;
    }

    @Override
    public <T> T find(Class<T> type, Object id) {
        return em.find(type, id);
    }

    @Override
    public <T> void delete(T t) {
        t = em.merge(t);
        em.remove(t);
    }

    @Override
    public <T> T update(T t) {
        return em.merge(t);
    }

    @Override
    public List findWithNamedQuery(String queryName) {
        return em.createNamedQuery(queryName).getResultList();
    }

    @Override
    public List findWithNamedQuery(String queryName, int resultLimit) {
        return em.createNamedQuery(queryName).setMaxResults(resultLimit)
                .getResultList();
    }

    @Override
    public List findWithNamedQuery(String namedQueryName,
                                   Map<String, Object> parameters) {
        return findWithNamedQuery(namedQueryName, parameters, 0);          
    }

    @Override
    public List findWithNamedQuery(String namedQueryName,
                                   Map<String, Object> parameters,
                                   int resultLimit) {
        Query query = this.em.createNamedQuery(namedQueryName);
        if(resultLimit > 0) {
            query.setMaxResults(resultLimit);            
        }
        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
            query.setParameter(entry.getKey(), entry.getValue());
        }
        return query.getResultList();
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T>  List<T> findWithNativeQuery(String sql, Class<T> type) {
        return em.createNativeQuery(sql, type).getResultList();
    }
}

See also

1 Most application shouldn't expose raw CRUD directly to clients but shield CRUD behind services implementing business rules and encapsulating access to Domain Stores (the EntityManager).

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • Sorry forgot to post the link to the blog, I have edited/added it. It is very similar to your solution, but states that "The interface-implementation is actually a Service, which always has to be executed behind a ServiceFacade" which I haven't figured out yet. – sdoca Jun 01 '10 at 05:10
  • It took me awhile to understand the generic classes (still getting a grasp on generics). But, I figured out what theymean/do. Thanks! – sdoca Jun 04 '10 at 21:25
  • Did your implementation above did what u said,`shield CRUD behinds services implementing business rules and encapsulate access to EntityManager`. It seems that you did not encapsulate access to `EntityManager`. How should you fix the above code to encapsulate `EntityManager`. One more question, when I try to access the EJB from my `Managed Bean`, I have to do `@EJB private GenericCrudService myEJB`, instead of `@EJB private GenericCrudServiceBean myEJB`. I thought the latter would make more sense because `GenericCrudService` is just and interface, `GenericCrudServiceBean` is a stateless bean – Thang Pham Apr 12 '11 at 17:49
  • I have couple more question about my solution, I post a new question here, please help: http://stackoverflow.com/questions/5641310/design-generic-crud-session-bean – Thang Pham Apr 12 '11 at 21:02