Вот три таблицы: product
, model
и product_model
, которые отображают продукты и модели в отношении N:M.
product product_model model
id name product_id model_id id name
------------ ------------------- ----------
p1 Product 1 p1 m1 m1 Model 1
p2 Product 2 p2 m1 m2 Model 2
... p2 m2
Что я хочу сделать: найти все продукты, поддерживающие модель 2 (например, product 2
). Затем для каждого продукта покажите список model_id, которые поддерживает продукт (product 2
=> [ m1
,m2
])
Это была моя первая попытка. Мне потребовалось еще N запросов для поиска model_id
s для каждого продукта.
# 1 query for searching products
my @products = $schema->resultset('Product')->search(
{ 'product_models.model_id' => 'm2' },
{ 'join' => 'product_model' },
)
# N queries for searching product_models for each product
foreach my $product ( @products ) {
my @model_ids = map { $_->model_id } $product->product_models;
# @model_ids = ( 'm1', 'm2' ) for p2
}
Я искал способ получить результат, используя только один запрос. Замена join
на prefetch
не сработала.
my @products = $schema->resultset('Product')->search(
{ 'product_models.model_id' => 'm2' },
{ 'prefetch' => 'product_model' }, # here
)
# no additional queries, but...
foreach my $product ( @products ) {
my @model_ids = map { $_->model_id } $product->product_models;
# now, @model_ids contains only ( `m2` )
}
Затем я попытался дважды выполнить предварительную выборку одной и той же таблицы:
my @products = $schema->resultset('Product')->search(
{ 'product_models.model_id' => 'm2' },
{ 'prefetch' => [ 'product_models', 'product_models' ] },
);
foreach my $product ( @products ) {
my @model_ids = map { $_->model_id } $product->product_models;
}
Казалось, мне это удалось. Был выполнен только один запрос, из которого я получил все идентификаторы моделей.
Однако я не был уверен, что это правильный(?) путь. Это правильный подход?
Например, если я использовал join
вместо prefetch
ing, Product 2
появится в цикле дважды. Я понимаю это, потому что объединенная таблица выглядит так:
id name p_m.p_id p_m.m_id p_m_2.p_id p_m_2.m_id
p2 Product 2 p2 m2 p2 m1
p2 Product 2 p2 m2 p2 m2 -- Product 2, one more time
Почему Product 2
появляется только один раз, когда я использую prefetch
?
Результирующие запросы почти одинаковы, за исключением разницы в SELECT
полях:
SELECT "me"."id", "me"."name",
"product_models"."product_id", "product_models"."model_id", -- only in prefetch
"product_models_2"."product_id", "product_models_2"."model_id" --
FROM "product" "me"
LEFT JOIN "product_model" "product_models"
ON "product_models"."product_id" = "me"."id"
LEFT JOIN "product_model" "product_models_2"
ON "product_models_2"."product_id" = "me"."id"
WHERE "product_models"."model_id" = 'm2'
DBIx::Class
— это ORM, где R означает «реляционный». В вашей схеме ожидаются отношения, такие какhas_many
илиbelongs_to
. После того, как они у вас есть, вам больше не нужно делать что-либо вне цикла вручную. Просто запрос наproduct_model
, который выбирает те строки, которые принадлежатproducts
, где имяeq
«Продукт 2» ... надеюсь, это даст вам достаточно подсказок. - person vanHoesel   schedule 18.12.2017product_model
иprefetch => { product => 'product_models' }
, чтобы получить все поддерживаемые модели. На самом деле я этого не делал, потому что в моей реальной работе есть еще несколько условий. Я подумаю еще и рассмотрю то, что вы сказали. Спасибо! - person gypark   schedule 19.12.2017