Основы Perl DBIC (предполагаю)

Вопрос или проблема

Некоторое время назад я прошел учебник по Node JS, который сильно полагался на использование ORM для доступа к базе данных. Несмотря на то, что мне вообще не понравился Node JS (он просто не для меня), мне понравилась концепция ORM. Так как Perl является моим языком сценариев по выбору, я решил углубиться в DBIx::Class, или DBIC. И я как-то застрял, пытаясь получить доступ к связанным данным с использованием соединений.

Я изучаю страницы MAN и в настоящее время читаю DBIx::Class::Manual::Joining.

Создал себе базу данных sqlite:

CREATE TABLE IF NOT EXISTS `cd` (
        `id` integer primary key NOT NULL UNIQUE,
        `cd_title` TEXT NOT NULL UNIQUE,
        `year` Text Not Null
);
CREATE TABLE IF NOT EXISTS `track` (
        `id` integer primary key NOT NULL UNIQUE,
        `cd_id` INTEGER NOT NULL,
        `track_title` TEXT NOT NULL UNIQUE,
        FOREIGN KEY(`cd_id`) REFERENCES `cd`(`id`)
);

Insert Into cd (id, cd_title, year) Values
        (1, 'CD 1', '2004'),
        (2, 'CD 2', '1995'),
        (3, 'CD 3', '2014'),
        (4, 'CD 4', '2024')
;
Insert Into track (id,cd_id,track_title) Values
        (1,1,'Track 1 CD 1'),
        (2,1,'Track 2 CD 1'),
        (3,1,'Track 3 CD 1'),
        (4,1,'Track 4 CD 1'),
        (5,1,'Track 5 CD 1'),
        (6,2,'Track 1 CD 2'),
        (7,2,'Track 2 CD 2'),
        (8,2,'Track 3 CD 2'),
        (9,3,'Track 1 CD 3'),
        (10,3,'Track 2 CD 3'),
        (11,3,'Track 3 CD 3'),
        (12,3,'Track 4 CD 3'),
        (13,3,'Track 5 CD 3'),
        (14,4,'Track 2 CD 4'),
        (15,4,'Track 3 CD 4'),
        (16,4,'Track 4 CD 4'),
        (17,4,'Track 5 CD 4')
;

По сути, 4 CD, каждый из которых имеет несколько треков. Файлы схемы были созданы с использованием dbicdump:

 dbicdump -o dump_directory=. Model::Schema dbi:SQLite:cds.sqlite

Файлы схемы довольно длинные, я вас от этого избавлю. Но так как dbicdump создал их, я предполагаю, что они корректны.

После этого я написал себе небольшой тестовый скрипт:

#! /usr/bin/env perl

use v5.20;
use Data::Dumper;
use DBIx::Class;
use lib '.';
use Model::Schema qw();
my $schema = Model::Schema->connect('dbi:SQLite:cds.sqlite');

my $cds = $schema->resultset('Cd')->search(
        {
                'cd_title' => { like => 'CD%'}
        },
        {

                join => 'tracks',
                order_by => ['tracks.id'],
        }
);

for my $cd ($cds->all()){
        say $cd->cd_title;
        say $cd->get_column('track_title');
}

Что-то вроде того, как говорит страница MAN. Но я не могу заставить это работать!

CD 1
DBIx::Class::Row::get_column(): No such column 'track.track_title' on Model::Schema::Result::Cd at ./test.pl line 24

shell returned 2

Он всё время жалуется, что не может найти столбец ‘track_title’ в таблице ‘track’. Я уже пробовал все возможные вариации имени столбца. Например, добавить имя таблицы, как ‘track.track_title’, но читая сообщение об ошибке, кажется, что это всё равно делает само по себе.

Похоже, он собирает все данные. Когда я убираю вторую строку ‘say’, он на самом деле выводит заголовок CD для каждого трека. Соединение, похоже, действительно работает.

Проверяя файл схемы ‘Track.pm’, я вижу, что добавляются следующие столбцы:

__PACKAGE__->add_columns(
  "id",
  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
  "cd_id",
  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
  "track_title",
  { data_type => "text", is_nullable => 0 },
);

Еще одна вещь, которую я заметил: пример на странице MAN использует сортировку по ‘tracks.id’. Где ‘tracks’ — это имя связи, а не имя таблицы. Вот почему я пробовал ‘$cd->get_column(‘tracks.track_title’)’ в ‘say’, без эффекта.

Я действительно хотел бы преодолеть это препятствие.

Петер

Ответ или решение

Основы Perl DBIx::Class: Работа с отношениями и объединениями

Недавно вы погрузились в использование DBIx::Class (DBIC), одного из самых мощных и популярных ORM (Object-Relational Mapping) инструментов для Perl. Вы столкнулись с определенными трудностями при работе с объединениями для доступа к связанным данным. Давайте разберем ваш вопрос и найдем решение.

Общий обзор вашей ситуации

Вы создали базу данных SQLite с таблицами cd и track, где каждая запись в таблице cd может иметь несколько записей в таблице track. Это нормальная реляционная структура, которая хорошо подходит для обработки с помощью ORM. Затем вы использовали команду dbicdump для генерации файлов схемы, которые обычно создают необходимые классы для работы с базой данных.

Ваша структура выглядит следующим образом:

  1. Таблица cd: Содержит информацию о музыкальных альбомах.
  2. Таблица track: Содержит информацию о песнях, связанных с определенным альбомом (по cd_id).

Проблема с объединением и доступом к связанным данным

Ваша ошибка проявляется, когда вы пытаетесь получить track_title через $cd->get_column('track_title'). Проблема заключается в том, что метод get_column работает только с колонками текущей модели, в данном случае с Cd, но не с связанными моделями (например, Track).

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

Правильный способ получения связанных данных

Вот как можно исправить ваш тестовый скрипт:

#! /usr/bin/env perl

use v5.20;
use Data::Dumper;
use DBIx::Class;
use lib '.';
use Model::Schema qw();

# Подключение к базе данных
my $schema = Model::Schema->connect('dbi:SQLite:cds.sqlite');

# Получение записей об альбомах
my $cds = $schema->resultset('Cd')->search(
    {
        'cd_title' => { like => 'CD%' }
    },
    {
        join => 'tracks',
        order_by => ['tracks.id'],
    }
);

# Вывод информации об альбомах и связанных треках
for my $cd ($cds->all()) {
    say $cd->cd_title;  # Печать названия альбома

    # Получение всех треков, связанных с альбомом
    my @tracks = $cd->tracks;  # Вызываем связь с треками
    for my $track (@tracks) {
        say $track->track_title;  # Печать названия каждого трека
    }
}

Объяснение изменений

  1. Получение треков: Вместо использования get_column, мы вызываем метод tracks, который возвращает все связанные записи из таблицы track для данного альбома.
  2. Итерация по трекам: После получения связанной коллекции треков, мы можем перебрать их с помощью цикла, выводя track_title.

Заключение

С помощью этого подхода вы сможете без проблем работать с связанными данными в DBIx::Class. Объединение и работа с отношениями – ключевые возможности ORM, и, изучая их, вы улучшите свои навыки в Perl и управлении данными. Если у вас возникнут дополнительные вопросы или сложности, не стесняйтесь обращаться за поддержкой. Удачи в вашем дальнейшем изучении DBIx::Class!

Оцените материал
Добавить комментарий

Капча загружается...