I've been working with Sequelize.js recently and come across the term "DAO" pretty frequently. Coming from ActiveRecord (in Rails), the idea of an ORM seems pretty straight forward.
Could someone explain to me what a DAO is? How does it differ from an ORM? How does it result in more modular code/prevent abstraction leaking?
Edit: After reading things like: https://www.reddit.com/r/learnprogramming/comments/32a1fr/what_is_the_general_difference_between_dao_and_orm/
It feels/seems like a DAO could be thought of as a singular "model" - as in the context of ActiveRecord, my User instance would be considered a DAO in that it: "abstracts the implementation of a persistent data store away from the application and allows for simple interaction with it"?
ORM and DAO are orthogonal concepts. One has to do with how objects are mapped to database tables, the other is a design pattern for writing objects that access data. You don't choose 'between' them. You can have ORM and DAO is the same application, just as you don't need ORM to use the DAO pattern.
So a DAO is just "an object that can execute SQL and return results in some basic data structure native to the programming language". An ORM will ultimately use a DAO to communicate with the database, but provides a whole lot more on top.
Sequelize is a Node. js-based Object Relational Mapper that makes it easy to work with MySQL, MariaDB, SQLite, PostgreSQL databases, and more. An Object Relational Mapper performs functions like handling database records by representing the data as objects.
Data Access Object Pattern or DAO pattern is used to separate low level data accessing API or operations from high level business services. Following are the participants in Data Access Object Pattern. Data Access Object Interface - This interface defines the standard operations to be performed on a model object(s).
I am not too familiar with ActiveRecord but yes, it sounds like your User instance is indeed a DAO.
The previous answer has some confusing aspects in it which I hope to clarify.
According to Oracle's description of the DAO pattern it:
- separates a data resource's client interface from its data access mechanisms
- adapts a specific data resource's access API to a generic client interface
The DAO pattern allows data access mechanisms to change independently of the code that uses the data.
That being said, manually executing a SQL statement using a language's SQL driver would almost never be referred to as a DAO. Firstly, it doesn't abstract the data access mechanism enough to be of any practical value. You couldn't, say, swap your DB for a NoSQL backend without having to reimplement ActiveRecord's execute
method to map SQL queries into the new backend's API.
That being said, some practical examples:
// Cloudscape concrete DAO Factory implementation
import java.sql.*;
public class CloudscapeDAOFactory extends DAOFactory {
public static final String DRIVER=
"COM.cloudscape.core.RmiJdbcDriver";
public static final String DBURL=
"jdbc:cloudscape:rmi://localhost:1099/CoreJ2EEDB";
// method to create Cloudscape connections
public static Connection createConnection() {
// Use DRIVER and DBURL to create a connection
// Recommend connection pool implementation/usage
}
public CustomerDAO getCustomerDAO() {
// CloudscapeCustomerDAO implements CustomerDAO
return new CloudscapeCustomerDAO();
}
public AccountDAO getAccountDAO() {
// CloudscapeAccountDAO implements AccountDAO
return new CloudscapeAccountDAO();
}
public OrderDAO getOrderDAO() {
// CloudscapeOrderDAO implements OrderDAO
return new CloudscapeOrderDAO();
}
...
}
As shown, the DAO factory sets up any connections with the underlying DB. This configuration is abstracted from the client.
// Interface that all CustomerDAOs must support
public interface CustomerDAO {
public int insertCustomer(...);
public boolean deleteCustomer(...);
public Customer findCustomer(...);
public boolean updateCustomer(...);
public RowSet selectCustomersRS(...);
public Collection selectCustomersTO(...);
...
}
As you can see, the DAO is meant to provide an object with a narrow interface to control and abstract access to the data layer. At any time, one could reimplement findCustomer
to query a NoSQL DB and the calling code wouldn't need to change. Thus "The DAO pattern allows data access mechanisms to change independently of the code that uses the data."
The DAO illustrated above may use an ORM library in the implementation to map the DB objects into models of the calling code or the implementation may perform the mapping itself. In any case, if the interface were changed so that findCustomer
returns a plain object and did no mapping, it would still be a DAO. A DAO does not need an ORM but often uses one.
An ORM can potentially perform all of its DB access using raw methods like the programming language's method for establishing TCP connections. So An ORM does not need a DAO but often uses one.
The fundamental feature of an ORM is that it maps DB objects into domain models. If an ORM library also handles communications with the DB, whether it uses a DAO or opens TCP connections to the DB, then it is itself also a DAO.
Here's some thoughts which might help clarify it for you. I'm more familiar with ActiveRecord than Sequelize, so I'll run with that, but the concepts should be the same for both.
You have a database. You can, completely independent of Rails (eg. using a database admin tool), go and run a query on that database - something like "select * from users limit 1"
. But that just gives you a set of results in some admin window, which aren't much use to your Rails app. You want to be able to execute SQL from your Rails app, and get data back in a form that Ruby/Rails can work with. You need to Access
your Data
through some kind of ruby Object
- you need a Data Access Object
, or DAO
.
In rails, you could run the query above with something like:
result = ActiveRecord::Base.connection.execute("select * from users limit 1")
The result
variable won't know or care about your User
model. All it will contain is essentially a list of plain ruby Hash
instances, like:
{
"id" => "1234",
"email" => "[email protected]",
"first_name" => "Fred",
"last_name" => "Flintstone",
}
If you wanted to update the first_name
to Bob
, you couldn't just edit that hash and call save on it - it's just a plain old hash, just the data and no extra smarts. So you'd have to write your own SQL again, and get Rails to execute it for you:
ActiveRecord::Base.connection.execute("update users set first_name = 'Bob' where id = 1234")
So what you're using in this context is basically just Rail's DAO
, without using it's ORM
.
The ORM
is like a layer on top of the DAO
. You can have a DAO
without an ORM
, but you can't have an ORM
without a DAO
. The ORM
, or Object Relational Mapper
will Map
concepts / records in your Relational
database with Objects
in your programming language (ie, Ruby). So, if you wanted to do the stuff above, using Rail's ORM
rather than using it's DAO
, it might look like:
user = User.find(1234)
user.name = 'Bob'
user.save!
See how much nicer it is using an ORM? Now, the snippet above, using the ORM, will still essentially just execute the same SQL we detailed earlier. The ORM just abstracts away more of the details and provides smarter objects to save us a bunch of extra work.
Again, the concepts demonstrated are transferable to Sequelize / Javascript and other langs/frameworks.
So a DAO
is just "an object that can execute SQL and return results in some basic data structure native to the programming language". An ORM
will ultimately use a DAO
to communicate with the database, but provides a whole lot more on top.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With