Что такое объектно-реляционное сопоставление (ORM)?

Что такое объектно-реляционное сопоставление (ORM)?

Содержание
  1. Организация
  2. DRY-код

Как программисты, мы всегда сталкиваемся с необходимостью представлять реальную информацию в виде кода в наших программах. Чтобы справиться с этой задачей, мы часто используем различные фреймворки или варианты дизайна для представления более абстрактных данных. Например, компания может захотеть отслеживать информацию о своих сотрудниках. Мы не можем представить все данные о каждом сотруднике, но мы можем определить конкретные, значимые аспекты, представляющие интерес, такие как имя сотрудника, его адрес, зарплата, отдел и т. д.

Одним из методов представления данных является объектно-реляционное отображение (ORM). Проще говоря, ORM - это шаблон проектирования, которому нужно следовать при использовании объектно-ориентированного языка с базой данных. Следуя соглашениям ORM, вы сможете сделать свой код более упорядоченным и ”чистым”.

Организация

Приложению может потребоваться доступ к сотням тысяч экземпляров базы данных. В то время как отдельные программисты могут придумывать свои собственные способы взаимодействия с одной и той же базой данных, следование соглашениям ORM обеспечивает структуру этого взаимодействия. Соблюдение соглашений упростит понимание кода как для вас, так и для других.

Чтобы понять ORM, мы должны сначала рассмотреть объектно-ориентированные языки. Объектно-ориентированные языки могут использовать классы для представления общих категорий вещей, таких как автомобили, кошки или сотрудники.

# код будет написан на Ruby
class Employee
  def initialize(name, address, salary)
    @name = name
    @address = address
    @salary = salary
    @@all << self
  end
end

Каждый класс может иметь экземпляры, уникальные индивиды внутри класса; Toyota Corolla, Tabby или John Smith. Экземпляры могут отличаться друг от друга, но в конечном итоге они относятся к общему классу.

employee1 = Employee.new("John Smith", "1684 Ravine Place Los Angeles, CA", 30000)
puts employee1.class # => Employee

employee2 = Employee.new("Jane Doe", "1909 Tower Rd Derry, ME", 43000)
puts employee2.class # => Employee

Зная это, мы можем упорядочить наш код, ”отобразив” его на базу данных в соответствии с соглашениями ORM. Мы создадим таблицу для каждого класса в нашей программе с одной строкой для представления каждого экземпляра класса. Для нашего класса Employee у нас будет таблица employees и две строки для двух наших сотрудников. Обратите внимание, что хотя имя нашего класса - единственное, имя нашей таблицы - множественное.

DRY-код

ORM также позволяет нам сохранять код DRY. Возвращаясь к нашему предыдущему примеру со списком сотрудников, наша программа должна иметь какое-то соединение с базой данных. В данном примере будет использоваться SQLite3.

database_connection = SQLite3::Database.new('db/company.db')

Теперь нам нужно создать таблицу для хранения информации о сотрудниках. Таблица создается путем передачи SQL в качестве аргумента метода execute. Мы попросим нашу программу создать таблицу с именем employees, если она еще не существует. Мы также назовем каждый столбец с типом данных для нашей таблицы employees, которая будет хранить различные значения в нашем классе Employee.

database_connection.execute(
    "CREATE TABLE IF NOT EXISTS employees("
    "id INTEGER PRIMARY KEY, "
    "name TEXT, "
    "address TEXT, "
    "salary INTEGER"
    ")"
)

Наша таблица создана, поэтому далее мы будем использовать атрибуты наших экземпляров для заполнения строк и соответствующих столбцов в нашей таблице базы данных. Обратите внимание, что мы не сохраняем непосредственно сам объект в таблицу, а обращаемся к атрибутам экземпляров и помещаем их в соответствующие столбцы нашей таблицы. Любые изменения в самой записи или экземпляре не приведут к автоматическому изменению других.

database_connection.execute("INSERT INTO employees (name, address, salary, VALUES ('John Smith', '1684 Ravine Place Los Angeles, CA', 30000)")
database_connection.execute("INSERT INTO employees (name, address, salary, VALUES ('Jane Doe', '1909 Tower Rd Derry, ME', 43000)")

Однако, как вы можете видеть, ручная вставка каждого экземпляра повторяется и будет становиться все более сложной и утомительной для поддержки, чем больше сотрудников мы добавим. Поэтому вместо этого мы можем создать метод экземпляра для нашего класса, который мы сможем использовать повторно.

Класс Employee
  def save(database_connection)
    database_connection.execute("INSERT INTO employees (name, address, salary) VALUES (?, ?, ?)", self.name, self.address, self.age)
  end
end

Наш метод #save примет в качестве параметра базу данных_соединения и вставит значения нашего экземпляра в соответствующие столбцы базы данных, которую мы предоставим. Теперь мы можем просто вызвать наш метод save для каждого экземпляра сотрудника и передать ему в качестве аргумента наше соединение с базой данных.

database_connection = SQLite3::Database.new('db/company.db')
Employee.all.each do |employee|
  employee.save(database_connection)
end

Даже когда наше приложение будет расти, нам больше не придется писать отдельные строки кода для сохранения наших классов в базе данных.

Хотя существует множество библиотек для различных языков программирования, которые помогают отображать объекты на базы данных. Эти библиотеки просто следуют определенным соглашениям, которые помогают упростить ваш код, если вы соблюдаете их схему. Короче говоря, Object-Relational Mapping (ORM) - это шаблон проектирования, который можно использовать при работе с объектно-ориентированным языком и базой данных. Несмотря на то, что существуют различные подходы, ORM следует конвенции отображения классов на таблицы и строк на экземпляры.

Источник