How can I select only specific columns when using

2019-05-09 14:09发布

问题:

I'm struggling with fairly fundamental DBIx-Class prefetch usage. I want to limit the columns that are returned from joined tables when prefetch is used.

This:

my $rs = $schema->resultset('CD')->search(
  {}, # No searching restrictions through WHERE clause
  {
    prefetch => [qw/ artist /],
    columns  => [qw/ title artist.name /],
  }
);

Generates this SQL:

SELECT cd.title, artist.*
FROM cd
JOIN artist ON cd.artist = artist.id

But I don't want to haul down all of the artist columns, just the cd.title and artist.name columns (in this example, my real use case is more complex). The columns feature seems to only work on the primary table rather than than joined tables as well.

I'd like this SQL:

SELECT cd.title, artist.name
FROM cd
JOIN artist ON cd.artist = artist.id

I'm just getting my sea-legs with Catalyst/DBIx-Class so I'm probably over-looking something blindingly obvious here!

回答1:

Yes, you are right. You can only select columns in the primary table, and can not get specific columns in the joined tables. What you need is join. use join and '+select','+as' property, you can select special columns from two tables.

Prefetch is used to select all columns from the prefetch tables as well. It is more efficient to use prefetch when you actually need those columns, e.g. so you can do $cd->artist->name without needing it to do the additional query. But if you don't need those columns then you have an unnecessary performance hit for loading up that data.



回答2:

Version 0.08250 of DBIx::Class supports prefetching a subset of columns. Now you can write a query with join, columns and the new collapse attribute which works like prefetch:

my $rs = $schema->resultset('CD')->search(
  {},
  {
    join     => [qw/ artist /],
    columns  => [qw/ title artist.name /],
    collapse => 1,
  }
);


回答3:

Additional. If you want to specify columns for nested joins (2 levels deep or more), you need to specify the columns using the hash format so that DBIx can resolve the relationships to apply to the column.

Example:

    my $rs = $schema->resultset('CD')->search(
      {},
      {
        join     => { 'artist' => { 'agent' => 'publisher' } },
        columns  => [qw/ title artist.name artist.agent.publisher_id /, 
                        { 'artist.agent.publisher.publisher_name' => 'publisher.publisher_name' } ],
        collapse => 1,
      }
    );