【问题标题】:Unable to Get Eloquent to Automatically Create Joins无法让 Eloquent 自动创建连接
【发布时间】:2012-06-21 09:50:15
【问题描述】:

如果我的问题的答案很明显,请提前道歉。在将其发布到此处之前,我已经尽职尽责地研究了该主题。

我的大部分框架经验都来自使用 CodeIgniter,所以我从来没有使用过 ORM 的实践经验。 (CI 确实有一些现成的 ORM 解决方案,但我从未使用过。)

我想在 Laravel 的 Eloquent ORM 中使用内置的 ORM 功能,在运行查询时自动将锦标赛和国家/地区表连接在一起,并返回包含锦标赛数据的数据集以及其相关的国家数据。

也就是说,我希望 Eloquent 自动识别外键关系,这样我就可以运行一个查询(例如 Tournament::with('Country')->all()),它会返回整个锦标赛集和国家数据。

如果我以从未打算使用的方式使用 Eloquent,请立即阻止我!我的困惑可能更多是因为我试图将一个站不住脚的解决方案混在一起,而不是语法或编码错误。

我想在 Eloquent 中复制的查询

SELECT * FROM tournaments LEFT JOIN countries ON tournaments.country_id = countries.id

PHP 中的预期结果

我希望收到一个 Tournament 对象数组(在 PHP 中),其中单个 Tournament 对象看起来像:

  • tournaments.id
  • tournaments.year
  • tournaments.country_id
  • tournaments.created_at
  • tournaments.updated_at
  • countries.id
  • countries.code
  • 国家/地区名称
  • countries.url
  • countries.created_at
  • countries.updated_at

我迄今为止的失败尝试

我在一个虚拟控制器方法中运行了所有这些尝试,并将结果作为格式化字符串输出到分析器。

尝试 #1 失败:

虚拟控制器中的 PHP 代码:

$tournaments = Tournament::with('Country')->all();

生成以下查询:

SELECT * FROM `tournaments`

尝试 #1 返回:

一个包含锦标赛对象的数组,这些对象仅包含锦标赛表中的列。

尝试 #2 失败

虚拟控制器中的 PHP 代码:

$tournaments = Tournament::with('Country')->first();

产生以下错误:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'tournament_id' in 'where clause'

SQL: SELECT * FROM `countries` WHERE `tournament_id` IN (?)

Bindings: array (
0 => '1',
)

其他失败的尝试

我尝试了各种命名约定组合(例如列、表等),但均无济于事。我还尝试在 Fluent 中创建查询,效果很好,但需要我指定我想要避免的连接。

我的环境

  • PHP:5.3.13
  • MySQL:5.1.53
  • Laravel:3.2.3

表之间的关系

  • 一对一的关系
  • 锦标赛必须有一个国家(有一个外键约束来强制它)
  • 一个国家/地区可以属于许多其他关系(例如,参与者,此处未显示,具有出生国家/地区)

国家/地区表

CREATE TABLE `countries` (                                                                                                                                                                                                                 
`id` int(11) NOT NULL AUTO_INCREMENT,                                                                                                                                                                                                       
`code` varchar(4) NOT NULL,                                                                                                                                                                                                                 
`name` varchar(25) NOT NULL,                                                                                                                                                                                                                
`url` varchar(25) NOT NULL,                                                                                                                                                                                                                 
`created_at` datetime NOT NULL,                                                                                                                                                                                                             
`updated_at` datetime NOT NULL,                                                                                                                                                                                                            
PRIMARY KEY (`id`),                                                                                                                                                                                                                        
UNIQUE KEY `countries_code_unique` (`code`),                                                                                                                                                                                               
KEY `countries_url_index` (`url`)                                                                                                                                                                                                          
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=latin1

锦标赛表

CREATE TABLE `tournaments` (                                                                                                                                                                                                             
`id` int(11) NOT NULL AUTO_INCREMENT,                                                                                                                                                                                                       
`year` int(11) NOT NULL,                                                                                                                                                                                                                    
`country_id` int(11) NOT NULL,                                                                                                                                                                                                              
`created_at` datetime NOT NULL,                                                                                                                                                                                                             
`updated_at` datetime NOT NULL,                                                                                                                                                                                                             
PRIMARY KEY (`id`),                                                                                                                                                                                                                         
UNIQUE KEY `tournaments_year_unique` (`year`),                                                                                                                                                                                             
KEY `tournaments_country_id_foreign` (`country_id`),                                                                                                                                                                                      
CONSTRAINT `tournaments_country_id_foreign` FOREIGN KEY (`country_id`) REFERENCES `countries` (`id`) ON UPDATE CASCADE                                                                                                                  
) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=latin1

国家模型 (countries.php)

class Country extends Eloquent {
    public static $timestamps = true;
    public static $table = 'countries';
}

锦标赛模型 (tournaments.php)

class Tournament extends Eloquent {
    public static $timestamps = true;

    public function country()
    {
        return $this->has_one('Country');
    }
}

【问题讨论】:

  • 这是一个写得很好的问题,先生,+1。
  • 这是一个写得很漂亮的问题。好工作! :)
  • 只删除这个:area51.stackexchange.com/proposals/46607/laravel

标签: php laravel laravel-3


【解决方案1】:

根据 Eloquent 文档:

注意:查询构建器上可用的所有方法在查询 Eloquent 模型时也可用。

所以考虑到这一点:

DB::table("tournament")->join("countries","tournaments.country_id","=","countries.id")->get();

应该可以在 Eloquent 中复制。我个人使用刚才您可能想要使用的查询构建器版本,但当我有机会并更新它时,我会尝试使用 Eloquent 进行测试。

更新:

是的,使用 Eloquent 的查询构建器方法,您可以获得:

Tournament::join("countries","tournaments.country_id","=","countries.id")->get();

这将返回一个包含两个表的字段的锦标赛模型。

HTH

【讨论】:

    【解决方案2】:

    您必须确保在锦标赛模型中声明了您的关系:

    public function country() {
        return $this->has_one('Country');
    }
    

    此外,您必须在 Country 模型中声明相反的内容:

    public function tournament() {
        return $this->belongs_to('Tournament');
    }
    

    此时,您可以像这样访问与国家对象关联的锦标赛对象:

    $tournaments = Tournament::with('country')->all();
    foreach ($tournaments as $tournament) {
        echo $tournament->country;
    }
    

    让我知道这是否显示了锦标赛的每个对应国家/地区。

    【讨论】:

      【解决方案3】:

      显然with('Country')with('country') 没有做任何不同,因为他设法得到以下错误:

      Column not found: 1054 Unknown column 'tournament_id' in 'where clause'
      
      SQL: SELECT * FROM `countries` WHERE `tournament_id` IN (?)
      

      错误的关系是如何定义的:锦标赛必须有一个国家将是一场锦标赛需要属于一个国家,而不是一个国家。所以要解决这个改变关系到

      public function country()
      {
          return $this->belongs_to('Country');
      }
      

      【讨论】:

      • 嗨@crynobone,感谢您的回复。为极其迟到的回复道歉。我转移了注意力,忘记了这个问题和具体问题。实施您的解决方案并没有完全得到预期的结果。它创建了两个单独的查询,一个在“国家”表上,另一个在“锦标赛”表上。我的首选结果是单个连接查询,该查询与我在“我希望在 Eloquent 中复制的查询”标题下的原始问题中提供的查询相匹配。如果我取得进展,我将再次回到这个问题并更新这个线程。
      • Laravel 急切加载不使用 JOIN 查询,这与其他 ORM 方法不同,据说仍然可以使用 Fluent Query Builder 结构的连接使用 Eloquent。 Tournament::query()->join('countries' ...);
      • 感谢您的回复,crynobone!太糟糕了,因为我真的很想尽可能多地使用 Eloquent 来生成查询。也就是说,Fluent Query Builder 绰绰有余。
      • @GrahamKennedy 这可能是一个迟到的回复。但是你没有得到想要的结果的原因是你使用了->all() 而不是->get() 方法。使用->get()方法,你会很惊讶
      • @GrahamKennedy 这个答案是正确的,值得被选为答案。
      【解决方案4】:

      您的“with”子句要求输入“国家”,但您的代码将其声明为“国家”。

      所以,应该:

      $tournaments = Tournament::with('Country')->all();
      

      是:

      $tournaments = Tournament::with('country')->all();
      

      因为在您的锦标赛模型中,您已将其定义为:

      public function country()
      {
          return $this->has_one('Country');
      }
      

      进行此更改是否可以解决问题?

      【讨论】:

      • 嗨@James Healey,感谢您的意见。不幸的是,外壳并没有解决问题。
      猜你喜欢
      • 2022-01-06
      • 2018-12-17
      • 1970-01-01
      • 2019-02-01
      • 1970-01-01
      • 2021-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多