DAO vs ORM - 在 Sequelize.js 的上下文中解释的概念
Posted
技术标签:
【中文标题】DAO vs ORM - 在 Sequelize.js 的上下文中解释的概念【英文标题】:DAO vs ORM - Concept explained in the context of Sequelize.js 【发布时间】:2017-05-20 14:11:09 【问题描述】:我最近一直在使用 Sequelize.js,并且经常遇到“DAO”这个词。来自 ActiveRecord(在 Rails 中),ORM 的想法似乎非常简单。
有人可以向我解释一下 DAO 是什么吗?它与 ORM 有何不同?它如何导致更多的模块化代码/防止抽象泄漏?
编辑:阅读后:https://www.reddit.com/r/learnprogramming/comments/32a1fr/what_is_the_general_difference_between_dao_and_orm/
感觉/似乎 DAO 可以被认为是一个单一的“模型”——在 ActiveRecord 的上下文中,我的用户实例将被认为是一个 DAO,因为它:“抽象实现远离应用程序的持久数据存储,并允许与它进行简单交互"?
【问题讨论】:
“原始查询”是一个specific example,其中 Sequelize.js 提到了DAO
:// Are you expecting a massive dataset from the DB, // and don't want to spend the time building DAOs for each entry? // You can pass an extra query option to get the raw data instead: Project.findAll( where: ... , raw: true )
【参考方案1】:
这里有一些想法可能会帮助您澄清它。我对 ActiveRecord 比对 Sequelize 更熟悉,所以我会使用它,但两者的概念应该相同。
你有一个数据库。您可以完全独立于 Rails(例如,使用数据库管理工具),在该数据库上运行查询 - 类似于 "select * from users limit 1"
。但这只是在一些管理窗口中为您提供一组结果,这对您的 Rails 应用程序没有多大用处。您希望能够从 Rails 应用程序执行 SQL,并以 Ruby/Rails 可以使用的形式获取数据。你需要Access
你的Data
通过某种红宝石Object
- 你需要一个Data Access Object
或DAO
。
在 Rails 中,您可以使用以下内容运行上述查询:
result = ActiveRecord::Base.connection.execute("select * from users limit 1")
result
变量不会知道或关心您的User
模型。它所包含的只是一个普通的 ruby Hash
实例列表,例如:
"id" => "1234",
"email" => "fred@example.com",
"first_name" => "Fred",
"last_name" => "Flintstone",
如果您想将first_name
更新为Bob
,您不能只编辑该哈希并对其调用保存 - 它只是一个普通的旧哈希,只是数据,没有额外的智能。因此,您必须再次编写自己的 SQL,并让 Rails 为您执行它:
ActiveRecord::Base.connection.execute("update users set first_name = 'Bob' where id = 1234")
所以你在这个上下文中使用的基本上只是 Rail 的DAO
,而不使用它的ORM
。
ORM
就像在DAO
之上的一层。你可以有一个没有ORM
的DAO
,但你不能有一个没有DAO
的ORM
。 ORM
或Object Relational Mapper
将Map
概念/记录在您的Relational
数据库中,Objects
使用您的编程语言(即Ruby)。所以,如果你想做上面的事情,使用 Rail 的 ORM
而不是使用它的 DAO
,它可能看起来像:
user = User.find(1234)
user.name = 'Bob'
user.save!
看看使用 ORM 有多好?现在,上面的 sn-p 使用 ORM,本质上仍然只是执行我们之前详述的相同 SQL。 ORM 只是抽象出更多细节并提供更智能的对象来为我们节省大量额外工作。
同样,所展示的概念可以转移到 Sequelize / javascript 和其他语言/框架。
所以DAO
只是“一个可以执行 SQL 并以编程语言原生的一些基本数据结构返回结果的对象”。 ORM
最终将使用 DAO
与数据库进行通信,但在上面提供了更多功能。
【讨论】:
很棒的反应。帮助澄清了很多,并证实了我脑海中的一些浮动“怀疑”。非常感谢。 相当不错的答案,需要添加更多视角。假设技术发生了变化,您决定使用不是可以使用 ActiveRecord 的 RDBMS 的数据存储。你的整个代码库很脆弱,因为它与特定后端的耦合度很高。 DAO 基本上是一个工厂,一个外观,一个抽象,允许您的应用程序在概念模型中工作,同时将存储、检索和修改后端的问题留给 DAO。【参考方案2】:我对 ActiveRecord 不太熟悉,但是是的,听起来您的 User 实例确实是一个 DAO。
上一个答案有一些令人困惑的方面,我希望澄清一下。
据Oracle's description of the DAO pattern它:
将数据资源的客户端接口与其数据访问机制分开 使特定数据资源的访问 API 适应通用客户端接口DAO 模式允许数据访问机制独立于使用数据的代码进行更改。
话虽如此,使用语言的 SQL 驱动程序手动执行 SQL 语句几乎永远不会被称为 DAO。首先,它没有将数据访问机制抽象足够 以具有任何实用价值。例如,您不能将数据库换成 NoSQL 后端,而不必重新实现 ActiveRecord 的 execute
方法以将 SQL 查询映射到新后端的 API。
话虽如此,一些实用的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();
...
如图所示,DAO 工厂 建立了与底层数据库的任何连接。这个配置是从客户端抽象出来的。
// 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(...);
...
如您所见,DAO 旨在为对象提供一个窄接口来控制和抽象对数据层的访问。在任何时候,都可以重新实现findCustomer
来查询 NoSQL DB,并且调用代码不需要更改。因此“DAO 模式允许数据访问机制独立于使用数据的代码进行更改。”
上面说明的 DAO 可以在实现中使用 ORM 库将 DB 对象映射到调用代码的模型中,或者实现可以自己执行映射。在任何情况下,如果接口被更改为 findCustomer
返回一个普通对象并且没有进行映射,它仍然是一个 DAO。 DAO 不需要 ORM,但经常使用 ORM。
一个 ORM 可以潜在地使用原始方法(例如用于建立 TCP 连接的编程语言的方法)执行其所有 DB 访问。所以ORM 不需要DAO,但经常使用DAO。
ORM 的基本特征是将数据库对象映射到域模型中。如果 ORM 库还处理与 DB 的通信,无论它使用 DAO 还是打开与 DB 的 TCP 连接,那么 它本身也是一个 DAO。
【讨论】:
以上是关于DAO vs ORM - 在 Sequelize.js 的上下文中解释的概念的主要内容,如果未能解决你的问题,请参考以下文章
Spring DAO vs Spring ORM vs Spring JDBC