Открыть сервис

Active Record

Active Record — это архитектурный шаблон (паттерн) проектирования, используемый в разработке программного обеспечения, при котором объект класса одновременно представляет строку таблицы реляционной базы данных и инкапсулирует логику доступа к данным и бизнес-логику. Шаблон был впервые описан Мартином Фаулером в книге «Patterns of Enterprise Application Architecture» (2002). Active Record является одним из наиболее распространённых подходов к реализации объектно-реляционного отображения (ORM).

История

Концепция, лежащая в основе Active Record, возникла как развитие идей, заложенных в ранних системах управления базами данных и объектно-ориентированных языках. В 1990-х годах, с ростом популярности веб-приложений, возникла потребность в упрощении взаимодействия между объектно-ориентированным кодом и реляционными базами данных. Разработчики искали способы уменьшить количество шаблонного кода (boilerplate code) для выполнения операций создания, чтения, обновления и удаления (CRUD).

Мартин Фаулер систематизировал существующие практики и выделил Active Record как отдельный паттерн. Он противопоставил его более сложному и абстрактному паттерну Data Mapper, который требует отдельного слоя для преобразования объектов в записи базы данных и обратно. Active Record, напротив, предлагает более простую и прямолинейную модель, где объект сам отвечает за свою персистентность.

Пик популярности шаблона пришёлся на середину 2000-х годов, во многом благодаря фреймворку Ruby on Rails, который сделал Active Record своей центральной частью. Успех Rails привёл к тому, что аналогичные реализации появились во многих других языках и фреймворках, включая Yii (PHP), Laravel (PHP), CakePHP (PHP), Django (Python), Entity Framework (C#) и другие.

Характеристики и принципы работы

Основная идея шаблона заключается в том, что класс, представляющий сущность предметной области (например, User, Order, Product), наследуется от базового класса Active Record. Этот базовый класс предоставляет набор методов для работы с базой данных.

Соответствие объекту и записи

Каждый экземпляр класса Active Record соответствует одной строке в таблице базы данных. Свойства объекта (поля класса) напрямую отображаются на столбцы таблицы. Например, если есть таблица users со столбцами id, name, email, то объект класса User будет иметь свойства id, name, email, значения которых соответствуют значениям в конкретной строке таблицы.

CRUD-операции

Active Record предоставляет встроенные методы для выполнения основных операций с базой данных:

  • Создание (Create): Метод save() или create(). Создаёт новую запись в таблице на основе значений свойств объекта.
  • Чтение (Read): Статические методы, такие как find(), find_by(), where(), all(). Позволяют извлекать одну или несколько записей из базы данных и возвращать их в виде объектов Active Record.
  • Обновление (Update): Метод save() или update(). После изменения свойств объекта вызов save() сохраняет изменения в соответствующей строке таблицы.
  • Удаление (Delete): Метод destroy() или delete(). Удаляет строку, соответствующую объекту, из таблицы.

Бизнес-логика

Помимо операций с базой данных, классы Active Record могут содержать методы, реализующие бизнес-логику, связанную с данной сущностью. Например, класс Order может содержать метод calculate_total(), который вычисляет общую сумму заказа, или метод is_shippable(), проверяющий, можно ли отправить заказ. Это позволяет объединить данные и поведение в одном объекте.

Валидации и связи

Современные реализации Active Record, как правило, включают встроенные механизмы для валидации данных (проверки корректности значений перед сохранением) и определения связей между моделями (например, «один ко многим», «многие ко многим»). Связи позволяют легко получать связанные объекты, например, получить все заказы конкретного пользователя через вызов user.orders().

Пример реализации (на псевдокоде)

```python

Базовый класс Active Record

class ActiveRecord: table_name = ""

def save(self): if self.id is None:

INSERT INTO {table_name} (col1, col2) VALUES (val1, val2)

self.id = database.insert(self.__dict__) else:

UPDATE {table_name} SET col1=val1, col2=val2 WHERE id=self.id

database.update(self.__dict__)

@classmethod def find(cls, id):

SELECT * FROM {table_name} WHERE id=id

data = database.query(f"SELECT * FROM {cls.table_name} WHERE id={id}") return cls(**data) if data else None

Конкретный класс-модель

class User(ActiveRecord): table_name = "users"

def __init__(self, name, email): self.id = None self.name = name self.email = email

Использование

user = User("Иван Иванов", "ivan@example.com") user.save() # Создаёт запись в БД

found_user = User.find(1) # Находит пользователя с id=1 print(found_user.name) # Выводит "Иван Иванов"

found_user.email = "new_email@example.com" found_user.save() # Обновляет запись в БД ```

Применение и популярные реализации

Ruby on Rails

Фреймворк Ruby on Rails (Rails) является наиболее известным и влиятельным примером использования шаблона Active Record. Его реализация, также называемая Active Record, является частью ядра Rails и предоставляет богатый набор функций, включая миграции базы данных, валидации, обратные вызовы (callbacks), ассоциации и механизмы наследования.

Yii (PHP)

Фреймворк Yii использует шаблон Active Record в своей ORM-системе. Класс yii\db\ActiveRecord является базовым для всех моделей. Yii поддерживает работу с несколькими базами данных, ленивую и жадную загрузку связанных данных, а также построение сложных запросов через объектный подход.

Laravel (PHP)

Фреймворк Laravel использует реализацию Active Record под названием Eloquent ORM. Eloquent отличается элегантным синтаксисом и тесной интеграцией с другими компонентами Laravel, такими как Blade (шаблонизатор) и Artisan (командная строка). Он поддерживает широкий спектр СУБД, включая MySQL, PostgreSQL, SQLite и SQL Server.

Django (Python)

ORM фреймворка Django (Object-Relational Mapping) также во многом следует принципам Active Record, хотя и имеет некоторые отличия. Классы моделей в Django наследуются от django.db.models.Model и предоставляют методы для работы с базой данных. Django ORM известен своей мощной системой построения запросов (QuerySet API) и автоматическим созданием схемы базы данных на основе определений моделей.

Entity Framework (C#)

Entity Framework (EF) от Microsoft, в особенности его «Code First» подход, также может рассматриваться как реализация шаблона Active Record. Классы, представляющие сущности, могут содержать как свойства, так и методы, а контекст базы данных (DbContext) управляет их персистентностью. Однако EF часто относят к гибридным решениям, сочетающим черты Active Record и Data Mapper.

Критика и ограничения

Несмотря на широкую популярность, шаблон Active Record имеет ряд недостатков, которые критикуются в сообществе разработчиков.

Нарушение принципа единственной ответственности (SRP)

Одним из главных критических замечаний является то, что Active Record нарушает принцип единственной ответственности (Single Responsibility Principle) из SOLID. Класс Active Record одновременно отвечает и за представление бизнес-сущности, и за взаимодействие с базой данных. Это может привести к тому, что классы становятся слишком большими и сложными, а их тестирование — затруднительным, так как требует наличия работающей базы данных.

Проблемы с тестированием

Из-за тесной связи с базой данных модульное тестирование (unit testing) классов Active Record затруднено. Для изоляции тестов необходимо использовать моки (mocks) или подменять базу данных на лёгкую in-memory СУБД, что не всегда тривиально. Интеграционное тестирование, напротив, становится более простым, так как не требует дополнительных слоёв абстракции.

Масштабирование и сложные запросы

При работе с очень сложными запросами, включающими множество соединений (joins), подзапросов и агрегаций, Active Record может стать менее эффективным. Генерация SQL-запросов через цепочки методов может быть менее гибкой и производительной, чем написание оптимизированного SQL-кода вручную. В таких случаях разработчики часто прибегают к написанию «сырых» SQL-запросов или использованию более низкоуровневых средств.

Смешение уровней

Active Record может способствовать смешению логики представления и бизнес-логики. Разработчики могут начать размещать логику, связанную с отображением данных (например, форматирование даты или имени), прямо в моделях, что затрудняет поддержку и переиспользование кода.

Сравнение с паттерном Data Mapper

Основной альтернативой Active Record является паттерн Data Mapper. В то время как Active Record делает объект ответственным за свою персистентность, Data Mapper вводит отдельный слой (маппер), который отвечает за передачу данных между объектами и базой данных. Объекты предметной области (Domain Objects) в паттерне Data Mapper являются «чистыми» POJO (Plain Old Java Objects) или POPO (Plain Old PHP Objects), не содержащими кода для работы с базой данных.

ХарактеристикаActive RecordData Mapper
ОтветственностьОбъект сам управляет своей персистентностьюОтдельный маппер управляет персистентностью
СложностьПроще в реализации и понимании для простых проектовСложнее, требует больше кода и абстракций
ТестированиеСложнее (требует БД или моков)Легче (объекты изолированы от БД)
ГибкостьМеньше (жёсткая связь с БД)Больше (можно менять мапперы и БД независимо)
ПримерыRuby on Rails, Laravel Eloquent, YiiDoctrine (PHP), Hibernate (Java)

Выбор между Active Record и Data Mapper зависит от сложности и требований проекта. Для небольших и средних приложений с простой бизнес-логикой Active Record часто является более быстрым и продуктивным решением. Для крупных, сложных систем с высокой нагрузкой и требованиями к тестируемости и гибкости Data Mapper может быть более предпочтительным.

Источники

  1. Фаулер М. «Шаблоны корпоративных приложений» (Patterns of Enterprise Application Architecture). — М.: Вильямс, 2006. — 544 с.
  2. Томас Д., Хэнссон Д. Х. «Ruby on Rails. Гибкая разработка веб-приложений» (Agile Web Development with Rails). — СПб.: Питер, 2014.
  3. Документация фреймворка Yii 2.0: «Active Record». — yiiframework.com.
  4. Документация фреймворка Laravel: «Eloquent: Getting Started». — laravel.com.
  5. Документация фреймворка Django: «Models and databases». — docs.djangoproject.com.
  6. Документация Microsoft Entity Framework Core. — docs.microsoft.com.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →