DAO 与 ORM - 在 Sequelize.js 的上下文中解释的概念

DAO vs ORM - Concept explained in the context of Sequelize.js

我最近一直在使用 Sequelize.js 并经常遇到术语 "DAO"。来自 ActiveRecord(在 Rails 中),ORM 的想法似乎非常简单。

谁能给我解释一下 DAO 是什么?它与 ORM 有何不同?它如何导致更模块化的 code/prevent 抽象泄漏?

编辑:阅读以下内容后:https://www.reddit.com/r/learnprogramming/comments/32a1fr/what_is_the_general_difference_between_dao_and_orm/

它 feels/seems 就像一个 DAO 可以被认为是一个单一的 "model" - 在 ActiveRecord 的上下文中,我的用户实例将被认为是一个 DAO,因为它:“从应用程序中抽象出持久数据存储的实现,并允许与它进行简单的交互"?

这里有一些想法可能有助于为您澄清。我对 ActiveRecord 比对 Sequelize 更熟悉,所以我会 运行,但两者的概念应该相同。

您有一个数据库。您可以完全独立于 Rails(例如,使用数据库管理工具),然后 运行 对该数据库进行查询 - 类似于 "select * from users limit 1"。但这只会在某些管理员 window 中为您提供一组结果,这些结果对您的 Rails 应用程序没有多大用处。您希望能够从 Rails 应用程序执行 SQL,并以 Ruby/Rails 可以使用的形式取回数据。您需要通过某种 ruby Object Access 您的 Data - 您需要 Data Access ObjectDAO.

在 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 之上的一层。你可以有一个没有 ORMDAO,但是你不能有一个没有 DAOORMORMObject Relational MapperMap 概念/记录在您的 Relational 数据库中,使用您的编程语言 Objects(即 Ruby)。所以,如果你想做上面的事情,使用 Rail 的 ORM 而不是使用它的 DAO,它可能看起来像:

user = User.find(1234)
user.name = 'Bob'
user.save!

看看使用 ORM 有多好?现在,上面的代码片段,使用 ORM,基本上仍然只是执行我们之前详述的相同 SQL。 ORM 只是抽象出更多的细节并提供更智能的对象来为我们节省大量额外的工作。

同样,演示的概念可转移到 Sequelize/Javascript 和其他 langs/frameworks。

所以 DAO 就是 "an object that can execute SQL and return results in some basic data structure native to the programming language"。 ORM 最终将使用 DAO 与数据库通信,但在顶部提供了更多。

我不太熟悉 ActiveRecord 但是是的,听起来您的 User 实例确实是一个 DAO。

之前的回答有一些比较混乱的地方希望澄清一下

根据Oracle's description of the DAO pattern它:

  • 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.

也就是说,使用语言的 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 factory 与底层数据库建立任何连接。此配置是从客户端抽象出来的。

// 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 数据库,并且调用代码不需要更改。因此 “DAO 模式允许数据访问机制独立于使用数据的代码进行更改。”

上面说明的 DAO 可以在实现中使用 ORM 库将 DB 对象映射到调用代码的模型中,或者实现可以自己执行映射。在任何情况下,如果接口被更改为 findCustomer returns 一个普通对象并且没有进行映射,它仍然是一个 DAO。 DAO 不需要 ORM 但经常使用 ORM。

ORM 可以使用原始方法(例如编程语言建立 TCP 连接的方法)潜在地执行其所有数据库访问。所以 ORM 不需要 DAO 但经常使用一个。

ORM 的基本特征是它映射 数据库对象到领域模型。如果 ORM 库还处理与 DB 的通信,无论它使用 DAO 还是打开与 DB 的 TCP 连接,那么它本身也是一个 DAO