Using Data Access Objects (DAO)
It is considered good practice to abstract the underlying persistence strategy away from the calling code, by encapsulating the persistence calls within Data Access Objects (DAOs). That means that your controller (or action) classes can have a DAO object injected, and use it, without having to worry how the data is persisted, or retrieved.
Morphia supports this style by providing an abstract BasicDAO implementation, based on the DAO interface, that uses the Datastore to persist, and query for java POJOs. This abstract class implements all the basic DAO methods you would want to use to create/update, read, and delete objects. It is provided as an example and pattern that you can use.
This means that by having your DAO class extend the BasicDAO class, you would normally only need to implement finder methods to return query results for you domain objects.
Let's look at how we could use the DAO support to manage blog entries. First of all, we would need to create a DAO class that extends BasicDAO<T,V>:
public class BlogEntryDAO extends BasicDAO<BlogEntry, ObjectId> {
public BlogEntryDAO( Morphia morphia, Mongo mongo ) {
super(mongo, morphia, "myBlogDb");
}
}Note that DAO uses generics to define a parameter class. This means you don't have to do any casting when using the DAO methods.
Since all the methods are implemented for us, we only need to do two important thing:
- Implement a constructor. The constructor passes information on to the DAO superclass.
- Implement finder methods
Now, we can use this class to persist and load blog entries:
...
BlogEntryDAO blogEntryDAO = new BlogEntryDAO(...);
// get one specific blog entry
ObjectId blogEntryId = ...;
BlogEntry myBlogEntry = blogEntryDAO.get(blogEntryId);
// update it
myBlogEntry.setTitle("My Blog Entry");
blogEntryDAO.save(myBlogEntry);
// or just delete it
blogEntryDAO.deleteById(myBlogEntry.getId());
...In a web application environment, we would probably use a dependency injection framework (like Guice or Spring) to inject the dependencies into the DAO, and then inject the DAO into a controller, so the controller would never directly deal with the gritty details.
This approach is highly recommended, as it keeps your code tidy and less prone to errors.
Custom finder methods
Although the abstract DAO implementation has find() methods, we sometimes need custom finder methods to filter the data, and apply custom sorting.
So, if we wanted to create a finder method that returns all blog entries where the title starts with a particular String (sorting in alphabetical order), we could add the following method to the BlogEntryDAO:
..
public List<BlogEntry> findByTitle( String title ) {
Pattern regExp = Pattern.compile(title + ".*", Pattern.CASE_INSENSITIVE);
return ds.find(entityClazz).filter("title", regExp).sort("title").asList();
}
...We perform the query, sorting the results (hopefully using an index), and then return the result as a list instead of as an iterator.
Name/Package Changes
In older versions of Morphia the dao class was called DAO but in newer versions there is a DAO interface, and BasicDAO implementation (to extend) now is their own package, "dao". The old class still exists for backwards compatibility but is marked as @ Deprecated.
In the example of the custom finder methods, the Query class doesn't have a method, sort(). You should replace it with the order() method.