Active Record vs Data Mapper

SeungHyuk Shin·2021년 9월 30일
1
post-thumbnail

라라벨을 사용하다보니 기본으로 지원해주는 ActiveRecord에 관심이 생겼다.스프링에서 JPA를 사용하던 느낌과는 매우 달랐다. 그래서 찾아보니 엘로퀀트는 Active Record Pattern의 ORM이고 JPA는 Data Mapper Pattern의 ORM이였다.

ORM의 패러다임


ORM(Object Relational Model)은 사물을 추상화시켜 이해하려는 OOP적 사고방식과 DataModel을 정형화하여 관리하려는 RDB 사이를 연결할 계층의 역할로 제시된 패러다임으로 RDB의 모델을 OOP에 Entity 형태로 투영시키는 방식을 사용한다.

이는 시스템에 따라, 사용하는 Database 및 DB Connector 에 따라 달라질 수 있는 데이터 매핑 구조를 객체지향형태로 통일시켜, SQL 구조의 Database를 OOP 구조의 형태로 매핑시키려는 패러다임이다.

Active Record


액티브 레코드 패턴의 객체의 인터페이스는 CRUD 기능을 하는 메서드들과 데이터베이스 테이블에 있는 컬럼에 해당하는 프로퍼티를 가진다.

액티브 레코드 패턴은 데이터베이스에 있는 데이터에 접근하는 방식이다. 데이터베이스 테이블은 클래스로 래핑된다. 따라서, 객체 인스턴스는 테이블의 열 하나에 해당하게 된다. 객체를 만들고 save하게 되면 테이블에 새로운 열이 추가된다. 마찬가지로 객체를 불러오면 그 객체는 데이터베이스의 정보를 그대로 가지고 있고, 객체를 업데이트하면 그 객체에 대응되는 열이 업데이트된다. 이 wrapper 클래스는 테이블이나 뷰의 각각의 컬럼에 대한 accessor 메서드(모델에서 데이터를 가져올때나 데이터를 업데이트 할 때 사용되는 메서드 )와 속성을 가지고 있다.

//laravel
class User extends Database
{
 public $firstname;
 public $lastname;
 public $age;
}

따라서 데이터베이스 클래스를 확장하여 만들기, 업데이트, 삭제 또는 읽기 작업을 쉽게 수행할 수 있다. 이것은 매우 생산성이 좋지만 큰 프로젝트에서 다음과 같은 문제를 일으킨다.

  • 테이블 스키마가 변경되면 코드를 수정해야 한다. 데이터베이스 테이블에서 age가 yearOfBirth로 열 이름이 변경되는 경우 코드에 모든곳에서 age을 yearOfBirth로 변경해야 한다.

  • 클래스를 데이터베이스 테이블에 직접 매핑하는 것은 안전하지 않다. 다른 사용자가 사용자를 만들어 잘못된 값을 전달할 수 있다.

Data Mapper


이와 달리, 데이터 매퍼에서 CRUD 작업을 쉽게 수행할 수 있는 액티브 레코드는 CRUD 작업을 위한 코드를 작성해야 한다. 데이터 매퍼는 더 많은 코드를 작성하지만 장기적으로는 유지 관리 및 수정하기가 더 쉽다.

데이터 매퍼는 영구적인 데이터 저장소(예를 들어, 관계형 데이터베이스)와 인메모리 데이터 표현 (도메인 레이어) 간의 양방향 데이터 전송을 수행하는 데이터 엑세스 레이어이다. Data Mapper 패턴의 목표는 인메모리 표현과 영구적인 데이터 저장소를 서로 독립적으로 유지시키고 데이터 매퍼 역할을 수행하는 것이다.

이 데이터 엑세스 레이어는 하나 이상의 매퍼로 구성되며, 데이터 전송을 수행한다. 일반적인 매퍼(generic mappers)는 여러 도메인 엔티티 타입을 다루고, 전용 매퍼(dedicated mappers)는 하나 또는 몇개만 처리한다.

위에 그림에서, 우리는 두 개의 클래스가 있다는 알 수 있다. User 및 User 매퍼이다. 사용자는 데이터베이스에서 매핑되거나 검색된 개념이 없는 엔티티 클래스이다. User 매퍼는 데이터베이스에서 모든 유형의 데이터를 가져와 사용자 클래스에 바인딩한다.

Datamapper 패턴을 구현하려면 Users Entity 클래스를 만들어야 한다.

엔터티는 확장되지 않거나 다른 클래스에 종속되지 않는 독립 클래스이다.

class Users
{
   public $firstName;
   public $lastName;
   public $age;
};

이제 엔터티 클래스 사용자가 있으므로 매퍼를 만들어야 한다. 이 엔터티를 테이블에 매핑한다. 데이터 매퍼의 좋은 점은 우리가 어떻게 매핑할지 결정한다는 것이다.

class UsersMapper
{
   public static function findById($id)
   {
      // 쿼리를 통해 결과 값 가져오기
      $query = "SELECT * FROM users WHERE id = $id";
       // 유저 엔티티의 인스턴스 생성 후 멤버에 매핑
      $user = new Users();
      $user->firstname = $databaseResult['first_name'];
      $user->lastName = $databaseResult['last_name'];
      $user->age = $databaseResult['age'];
      return $user;
   }
}

0개의 댓글