0

I'm currently thinking about how i handle my domain objects along with hibernate considering the following :

  • My model object are directly annotated with JPA annotation, no entity layer.
  • On some database heavy operation, i don't mind tuning my code so i take full advantages of the proxies, even if we can consider it as a leak of abstraction/implementation masking. Of course i prefer when i can do otherwise.
  • Because i don't have entity layer, i don't have a DAO layer, the entity manager is considerered itself as a DAO layer (related : I found JPA, or alike, don't encourage DAO pattern)

However i was thinking about improve what i'm doing know in order to reduce a bit the complexity, or at least, relocate that complexity in a place it fits better, like entity's related service. And maybe more abstract the fact that i'm using an ORM.

Here is a generic CRUD Service from which all my business service inherits. This code is to show you how things are done currently (annotation, logs remove for clarity) :

public void create(T entity) {
    this.entityManager.persist(entity);
}
@Transactional(value = TxType.REQUIRED, rollbackOn=NumeroVersionException.class)
public void update(T entity) throws NumeroVersionException{
    try{
        this.entityManager.merge(entity);
    }catch(OptimisticLockException ole){
        throw new NumeroVersionException("for entity "+entity, ole);
    }
}

public T read(int id) {
    return this.entityManager.find(entityClass, id);
}
public void delete(int id) {
    T entity = this.entityManager.getReference(entityClass, id);
    this.entityManager.remove(entity);
    // edit : removed null test thanks to @JBNizet
}

The problem with this kind of implementation, is that if i want to create an object, then use the advantages of the proxies i basically have to create it then refetch it. Of course the query may not hits the database but hits only hibernat's cache (not sure about it though). But that means i still have to not forget to refetch the proxy.

This mean i leak the fact that i'm using an ORM and proxies behind the scenes.

So i was thinking to change my interface to something like :

public T read(int id);
public T update(T t)throws NumeroVersionException;
public T create(T object);
public void delete(int id);
List<T> list();

Meaning once i pass an object to this layer, i will have to use the returned value. And implements update specifically like :

public T update(T t){
    if(!(t instanceof [Proxy class goes there])){
        //+ check if it is a detached proxy
        entityManager.merge(t);
    }  
}

Since merge hits the database every time called, for some operation involving just some 10ish entities this can be annoying i wouldn't call it in an update method with a proxy.

Of course I expect to have some edge cases where i'll need the entityManager to flush things and so on. But i think this would reduce significatively the current complexity of my code and isolate better the concerns.

What i'm trying in short is to relocate the ORM code within the service so i can hide the fact that i'm using an ORM and proxies and use the interface like i was using any other implementation without loosing the benefits of using an ORM.

The question is so :

  1. Is that new design a good idea towards this idea ?
  2. Did i miss anything about how to handle this properly ?

Note : Even though i'm talking about performance, my concern is also about isolation of concerns, maintenability, and easier usability for developers that aren't familiars with ORMs and Java which i work with.

Community
  • 1
  • 1
Walfrat
  • 5,363
  • 1
  • 16
  • 35
  • I have a hard time understanding what you're asking. You say you don't have DAOs, but the service you're showing **is** a DAO: no business logic at all, and purely persistence-related operations. merge() returns an entity for good reasons, and since your update() method dimply calls merge(), of course it should return the entity. Regarding proxies, I have no idea what your concern is. You shouldn't have to care whether you get a proxy or not from Hibernate, and whether update() receives a proxy or not. – JB Nizet Jun 14 '16 at 12:20
  • BTW, update()/merge() are almost never needed. Typically, you get a managed entity from a find() or a query, modify it, and that's all. JPA makes the changes persistent automatically. – JB Nizet Jun 14 '16 at 12:20
  • @JBNizet I have more methods than this, this class is a generics that handle crud operation from which my true service layer inherits. Some override this to add business logic and then rely to super.create/update to handle enntity part – Walfrat Jun 14 '16 at 12:43
  • @JBNizet In fact my problem is : on a higher level than a service, should i use my objects like they're ORM proxies (will get updated automatically and si on) or should I use them as my implementation of the service could be anything else than an ORM ? – Walfrat Jun 14 '16 at 12:47
  • @JBNizet : I edited my post to try to get my question easier to understand. i also took into account the getReference() point too – Walfrat Jun 14 '16 at 13:05
  • Ah. I start seeing what you mean by proxies. All managed entities are not proxies. Most are not, actually. So if I understand correctly, you're wondering if you should implement your services by relying on the fact that they use managed entities, or should you treat them as detached POJOs. Yes, of course you should rely on the fact that they're managed. Not doing it would be either very hard to do, or not efficient at all. If you choose JPA, you choose it for the advantages it offers. You won't switch anyway. – JB Nizet Jun 14 '16 at 13:41
  • @JBNizet Can you make an answer of this so i can accept it ? – Walfrat Jun 14 '16 at 14:11

1 Answers1

0

Thanks to @JBNizet i'm seeing some thing more clearly :

  • I should use the value returned by merge() method.
  • A managed entity is not always a proxy.
  • I don't have to abstract the fact that i use managed entities, this will lead to complex and unefficient code
  • I choosed JPA i won't switch for it which is true unless rewriting the full model to stand for something based on non relationnal database.

So i'll just change my update method from the original code and i'll keep the rest.

Walfrat
  • 5,363
  • 1
  • 16
  • 35