-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 49 posts ]  Go to page 1, 2, 3, 4  Next
Author Message
 Post subject: DAO implementations
PostPosted: Tue Oct 28, 2003 12:22 pm 
Newbie

Joined: Mon Oct 27, 2003 6:41 pm
Posts: 7
Does anyone have some good ideas or examples of how to implement a DAO using Hibernate?

I am interested in how you implemented your CRUD methods.

Thanks


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 28, 2003 12:36 pm 
Regular
Regular

Joined: Tue Aug 26, 2003 3:34 pm
Posts: 54
Location: Farroupilha - Brasil
One simple ...

[code]
public class User {
private int id;
private String login;
private String password;
private String name;
......
private Set groups;

private Set companies;
}

public class HibernateUserDAO {

private HibernateFactory factory;

public HibernateUserDAO() {
factory = HibernateFactory.getInstance();
}

public User select(int id) throws HibernateException {
User res = null;
Session session = null;
try {
session = factory.openSession();
res = (User) session.load(User.class, new Integer(id));

} catch (net.sf.hibernate.ObjectNotFoundException h1) {
throw h1;
} catch (HibernateException h2) {
throw h2;
} finally {
factory.closeSession(session);
}

return res;
} //select(int)

/**
* Seleciona um usu


Top
 Profile  
 
 Post subject: Exception handling inside the DAO
PostPosted: Tue Oct 28, 2003 1:51 pm 
Newbie

Joined: Mon Oct 27, 2003 6:41 pm
Posts: 7
How did you decide to handle the exceptions? Would it be better to handle all exceptions inside the DAO or re-throw them up to the calling class? Why?

If your DAO implements an interface, wouldn't each Class that implements it will have to throw those exceptions too?

Thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 28, 2003 2:08 pm 
Regular
Regular

Joined: Tue Aug 26, 2003 3:34 pm
Posts: 54
Location: Farroupilha - Brasil
I prefer to re-throw the exceptions ... thus I can treat the errors in the other application layers.

In the reality I use an interface ... all the methods in throws Exception ....

Code:
public interface UserDAO {
   public User select(int id)  throws Exception;
   public  User insert(User user) throws Exception;
}

public class JDBCUserDAO implements UserDAO {
   public User select(int id) throws SQLException {
      ....
   }
}

public class HibernateUserDAO implements UserDAO {
   public User select(int id) throws HibernateException {
      ....
   }
}

public class XMLUserDAO implements UserDAO {
   public User select(int id) throws IOException {
      ....
   }
}



Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 28, 2003 2:11 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 3:00 pm
Posts: 1816
Location: Austin, TX
Quote:
Would it be better to handle all exceptions inside the DAO or re-throw them up to the calling class?

re-throw them.

Quote:
Why?

Because the DAO is simply a helper, not a control component. As such, it should not be making decisions about how to handle exception conditions.

Here is one of mine:
Code:
public interface PersonDao
{
    public Person load(Long id) throws LocateException;
    public List load(Collection ids) throws LocateException;

    public Person findByUserName(String username) throws SearchException;
    public List findForMatch(PersonMatchCriteria criteria) throws SearchException;

    public Person create(Person person) throws CreationException, ValidationException;
    public Person update(Person person) throws SaveException, ValidationException;
    public void delete(Person person) throws RemovalException, ValidationException;

    public Person newEntity();
}


And the hibernate-specific impl:
Code:
public class PersonDaoImpl extends AbstractDao
implements PersonDao
{
    private static final Logger log = Logger.getLogger( PersonDaoImpl.class );

    public PersonDaoImpl() {}

    public Person load(Long id)
    throws LocateException
    {
        if (id == null)
            return null;

        Session session = obtainSession();
        try
        {
            return (Person)session.load(PersonImpl.class, id);
        }
        catch(Throwable t)
        {
            log.warn( "Unable to load requested person [id=" + id + "]", t );
            throw new LocateException( "Unable to load requested person [id=" + id + "]", t );
        }
        finally
        {
            releaseSession(session);
        }
    }

    public List load(Collection ids)
    throws LocateException
    {
        if (ids == null || ids.isEmpty())
            return Collections.EMPTY_LIST;

        Session session = obtainSession();
        try
        {
            Query query = session.createQuery( "from PersonImpl as dmn where dmn.id IN (:idList)" );
            query.setParameterList( "idList", ids );
            return query.list();
        }
        catch(Throwable t)
        {
            log.warn( "Unable to load requested persons [ids=" + ids + "]", t );
            throw new LocateException( "Unable to load requested persons [ids=" + ids + "]", t );
        }
        finally
        {
            releaseSession(session);
        }
    }

    public Person findByUserName(String username)
    throws SearchException
    {
        Session session = obtainSession();
        try
        {
            List tmp = session.find(
                    "from PersonImpl as p where p.userName = ?",
                    username,
                    Hibernate.STRING
            );

            if (tmp != null)
                return (Person)tmp.get( 0 );
            else
                return null;
        }
        catch( Throwable t )
        {
            log.warn( "Unable to perform person find by username", t );
            throw new SearchException(  "Unable to perform person find by username", t );
        }
        finally
        {
            releaseSession( session );
        }
    }

    public List findForMatch(PersonMatchCriteria criteria)
    throws SearchException
    {
        Session session = obtainSession();
        try
        {
            String queryString = "select p from PersonImpl as p where true=true";

            List queryParameters = new ArrayList();
            if (criteria != null && !criteria.isEmpty())
            {
                if (criteria.getFirstName() != null)
                {
                    queryString += " and (soundex(p.name.firstName) = soundex(:firstName) ";
                    queryString += " or soundex(p.name.familiarName) = soundex(:firstName)) ";

                    queryParameters.add(
                            new HibernateQueryParameter(
                                    "firstName",
                                    criteria.getFirstName(),
                                    Hibernate.STRING
                            )
                    );
                }

                if (criteria.getLastName() != null)
                {
                    queryString += " and soundex(p.name.lastName) = soundex(:lastName) ";
                    queryParameters.add(
                            new HibernateQueryParameter(
                                    "lastName",
                                    criteria.getLastName(),
                                    Hibernate.STRING
                            )
                    );
                }

                if (criteria.getEmail() != null)
                {
                    queryString += " and upper(p.email) = upper(:email) ";
                    queryParameters.add(
                            new HibernateQueryParameter(
                                    "email",
                                    criteria.getEmail(),
                                    Hibernate.STRING
                            )
                    );
                }
            }

            Query query = session.createQuery( queryString );
            HibernateQueryParameter.bindParametersToQuery(queryParameters, query);
            return query.list();
        }
        catch( Throwable t )
        {
            log.warn( "Unable to perform person-match find", t );
            throw new SearchException(  "Unable to perform person-match find", t );
        }
        finally
        {
            releaseSession( session );
        }
    }

    public Person create(Person person)
    throws CreationException, ValidationException
    {
        Session session = obtainSession();
        try
        {
            session.save(person);
            return person;
        }
        catch(ValidationExceptionRuntimeWrapper e)
        {
            throw e.getWrappedValidationException();
        }
        catch(Throwable t)
        {
            log.warn( "Unable to create person", t );
            throw new CreationException( "Unable to create person", t );
        }
        finally
        {
            releaseSession(session);
        }
    }

    public Person update(Person person)
    throws SaveException, ValidationException
    {
        Session session = obtainSession();
        try
        {
            return person;
        }
        catch(ValidationExceptionRuntimeWrapper e)
        {
            throw e.getWrappedValidationException();
        }
        catch(Throwable t)
        {
            log.warn( "Unable to update person", t );
            throw new SaveException( "Unable to update person", t );
        }
        finally
        {
            releaseSession(session);
        }
    }

    public void delete(Person person)
    throws RemovalException, ValidationException
    {
        Session session = obtainSession();
        try
        {
            session.delete(person);
        }
        catch(ValidationExceptionRuntimeWrapper e)
        {
            throw e.getWrappedValidationException();
        }
        catch(Throwable t)
        {
            log.warn( "Unable to delete person", t );
            throw new RemovalException( "Unable to delete person", t );
        }
        finally
        {
            releaseSession(session);
        }
    }
}


Note that all the exceptions are application defined exceptions...

HTH


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 28, 2003 3:41 pm 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
Code:
public interface PersonDao
{
    public Person load(Long id) throws LocateException;
    public List load(Collection ids) throws LocateException;

    public Person findByUserName(String username) throws SearchException;
    public List findForMatch(PersonMatchCriteria criteria) throws SearchException;

    public Person create(Person person) throws CreationException, ValidationException;
    public Person update(Person person) throws SaveException, ValidationException;
    public void delete(Person person) throws RemovalException, ValidationException;

    public Person newEntity();
}


Looks like this kind of code ( with implementation) is trivial to generate, is not it ? I do not think it is a good idea to write it manualy.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 28, 2003 3:51 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 3:00 pm
Posts: 1816
Location: Austin, TX
The interface probably would using something like meta tags in the mapping. How are you thinking the impls would be trivial to generate, though?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 28, 2003 4:18 pm 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
I was going to implement it in voruta, but it must be poosible to use hibernate metadata to generate more "clever" code. I prefer to generate this kind of things at runtime, velocity template must be a good way too (easy to customize and debug generated code).

I am not sure about the "best" code in implementation, but I am sure it is possible to generate it.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 28, 2003 5:03 pm 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
I prefer convenience libraries to code generation - after all, generated code has to be maintained somehow. And with DAOs, finder methods etc need to be hand-coded anyway.

For a different way of writing DAOs, let me show how the Spring Framework eases DAO implementation, with a source example from the Petclinic (a sample app that comes with the Spring distribution):

Code:
public class HibernateClinic extends HibernateDaoSupport implements Clinic {

  public List getVets() {
    return getHibernateTemplate().find("from Vet vet order by vet.lastName, vet.firstName");
  }

  public List getPetTypes() {
    return getHibernateTemplate().find("from PetType type order by type.name");
  }

  public List findOwners(String lastName) {
    return getHibernateTemplate().find("from Owner owner where owner.lastName like ?", lastName + "%");
  }

  public Owner loadOwner(long id) {
    return (Owner) getHibernateTemplate().load(Owner.class, new Long(id));
  }

  public Pet loadPet(long id) {
    return (Pet) getHibernateTemplate().load(Pet.class, new Long(id));
  }

  public void storeOwner(Owner owner) {
    getHibernateTemplate().saveOrUpdate(owner);
  }

  public void storePet(Pet pet) {
    getHibernateTemplate().saveOrUpdate(pet);
  }

  public void storeVisit(Visit visit) {
    getHibernateTemplate().saveOrUpdate(visit);
  }
}


All of those data access methods are effectively one-liners but still offer proper resource handling (Session opening and closing) and transaction participation. HibernateDaoSupport is a convenience base class that offers a "sessionFactory" bean property and prepares a HibernateTempate instance. You can also choose to instantiate your own HibernateTemplate for any given SessionFactory.

The above methods are just convenience methods that avoid the need for a callback implemenation. The "standard" way of using HibernateTemplate is like as follows. Note that HibernateTemplate will automatically convert HibernateExceptions into Spring's unchecked generic DataAccessException hierarchy. You're free to add any exceptions with business meaning to the DAO method signatures.

Code:
  public List findOwners(String lastName) {
    return (List) hibernateTemplate.execute(
      new HibernateCallback() {
        public Object doInHibernate(Session session) throws HibernateException {
          return session.find("find("from Owner owner where owner.lastName like ?", lastName + "%", Hibernate.STRING);
        }
      }
  });


The HibernateClinic bean is configured in a Spring application context as follows, referencing a SessionFactory defined in the context:

Code:
<bean id="clinic" class="org.springframework.samples.petclinic.hibernate.HibernateClinic">
  <property name="sessionFactory"><ref bean="sessionFactory"/></property>
</bean>


Of course, you can also instantiate it without an application context, as it is a simple bean:

Code:
HibernateClinic clinic = new HibernateClinic();
clinic.setSessionFactory(sessionFactory);


All of the above DAO methods automatically participate in transactions driven by Spring's transaction management. Demarcation can happen programmatically or declaratively (on POJOs), and the actual transaction strategy is pluggable. For Hibernate, HibernateTransactionManager (for a single SessionFactory) and JtaTransactionManager are appropriate; both implicitly use ThreadLocal Sessions underneath.

The article at http://www.hibernate.org/110.html gives a detailed overview. I'll be happy to discuss it further if you're interested.

Juergen


Top
 Profile  
 
 Post subject: Steve, can you post AbstractDAO?
PostPosted: Tue Oct 28, 2003 6:24 pm 
Newbie

Joined: Tue Oct 28, 2003 6:00 pm
Posts: 14
I am working on DAO for my application, and would like to see how you implement obtainSession() and releaseSession(). Thanks, Barry


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 28, 2003 6:27 pm 
Newbie

Joined: Tue Oct 28, 2003 6:00 pm
Posts: 14
My previous question was for Steve. Steve, can you post source for AbstractDAO? I am looking for implementation on obtainSession() and releaseSession().


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 28, 2003 7:07 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 7:19 pm
Posts: 2364
Location: Brisbane, Australia
Most likely steve is using the ThreadLocal pattern which is documented on the wiki.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 28, 2003 8:35 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 3:00 pm
Posts: 1816
Location: Austin, TX
Sorry, battling the new braindead weblogic JMX implementation...

These DAOs use spring, so the base impl looks like:
Code:
public abstract class AbstractDao
extends HibernateDaoSupport
{
    protected final Logger log = Logger.getLogger(getClass());
    private UserResolver userResolutionStrategy;

    /** Creates a new instance of AbstractDao
     */
    public AbstractDao()
    {
    }

    protected Session obtainSession()
    {
        return SessionFactoryUtils.getSession( getSessionFactory(), false );
    }

    protected void releaseSession( Session session )
    {
        // Do nothing...
    }

    protected User getCurrentUser()
    {
        return userResolutionStrategy.getCurrentlyExecutingUser();
    }

    public UserResolver getUserResolutionStrategy()
    {
        return userResolutionStrategy;
    }

    public void setUserResolutionStrategy(UserResolver userResolutionStrategy)
    {
        this.userResolutionStrategy = userResolutionStrategy;
    }
}


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 28, 2003 9:35 pm 
Newbie

Joined: Sun Oct 05, 2003 4:29 pm
Posts: 14
Location: Toronto, Canada
Steve,

This is good stuff, why not paste the rest of the code, or put it up on the wiki?

john


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 29, 2003 12:08 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 3:00 pm
Posts: 1816
Location: Austin, TX
Sure, I'll paste the rest. What else did you want to see?

Not sure that its so good for the Wiki, as everyone has different preferences for implementing components. Like mine span only a single domain entity; while Juergen's span multiple. Little variations like that make it difficult to say "here's how you do it". Programming is almost as much art as it is science :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 49 posts ]  Go to page 1, 2, 3, 4  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.