为什么我在DBIx :: Class中为'has_many'关系获得'JOIN'而不是'LEFT JOIN'?

时间:2015-05-07 18:20:44

标签: perl join dbix-class

我在下一个关系中有三张桌子:

package SafeVPN::DB::Result::Locality;
__PACKAGE__->has_many( servers        => 'SafeVPN::DB::Result::Server', 'locality_id', {cascade_delete => 0});
__PACKAGE__->has_many( addresses_view => 'SafeVPN::DB::Result::Pool::Address_view', 'locality_id', {cascade_delete => 0});

package SafeVPN::DB::Result::Server;
__PACKAGE__->has_many('addresses_view', 'SafeVPN::DB::Result::Pool::Address_view', 'server_id', {cascade_delete => 0});
__PACKAGE__->belongs_to('locality', 'SafeVPN::DB::Result::Locality', 'locality_id', {cascade_delete => 0});


package SafeVPN::DB::Result::Pool::Address_view;
__PACKAGE__->belongs_to( server   => 'SafeVPN::DB::Result::Server',       'server_id'  );
__PACKAGE__->belongs_to( locality => 'SafeVPN::DB::Result::Locality',     'locality_id');
__PACKAGE__->belongs_to( subnet   => 'SafeVPN::DB::Result::Pool::Subnet', 'subnet_id'  );

在Locality.pm中运行
这:$self->search_related('servers')->search_related('addresses_view')->as_query
或者:$self->servers->search_related('addresses_view')->as_query

生成下一个查询:

SELECT 
  "addresses_view"."id", "addresses_view"."subnet_id", 
  "addresses_view"."ip", "addresses_view"."usage",
  "addresses_view"."notes", "addresses_view"."locality_id", 
  "addresses_view"."server_id" 
FROM "servers" "me"  
JOIN "pool_addresses_view" "addresses_view" 
  ON "addresses_view"."server_id" = "me"."id" 
WHERE ( "me"."locality_id" = ? )

但依赖'has_many'关系(doc说:“这种关系在外表中引用零个或多个记录(例如LEFT JOIN)”

我希望'LEFT JOIN'但是,如你所见,我得到'JOIN'

因此,如果'locality_id'中的'server'没有ip地址,我会从结果中删除'server'

更新
添加属性 join_type => 'left'喜欢:

__PACKAGE__->has_many( addresses_view => 'SafeVPN::DB::Result::Pool::Address_view', 'locality_id', {cascade_delete => 0,join_type => 'left'});
__PACKAGE__->has_many('addresses_view', 'SafeVPN::DB::Result::Pool::Address_view', 'server_id', {cascade_delete => 0,join_type => 'left'});

无效。也许是BUG?

1 个答案:

答案 0 :(得分:3)

嗯,servers->search_related('addresses_view')表示“我想要此服务器的地址”而不是“此地址服务器”,因此没有必要这样做{{ 1}},它会在结果中保存没有地址的服务器,但你不再关心服务器了(LEFT JOIN意味着什么)。

search_related会返回新类型的结果集:search_related而不是SafeVPN::DB::ResultSet::Pool::Address_view

如果您想获取带有地址的服务器(即保留结果集类型,但添加一些额外信息),那么您可能希望使用prefetch,而不是SafeVPN::DB::ResultSet::Pool::Server

search_related

您没有获得原始连接关系,所有地址都存储在my @servers = $self->servers->search({}, prefetch => 'addresses_view')->all(); foreach my $server (@servers) { print $server->addresses_view(); # Doesn't make a SQL query, data is *prefetched*. } 结果对象中,这就是ORM的工作方式。