laravel BelongsTo与不同数据库的关系不起作用

NiR*_*iRR 18 laravel

我已经在几个地方看到"远离"这个,但唉 - 这就是我的数据库的构建方式:

class Album extends Eloquent {

   // default connection

   public function genre() {
       return $this->belongsTo('genre');
   }
Run Code Online (Sandbox Code Playgroud)

和流派表:

class Genre extends Eloquent {
    protected $connection = 'Resources';

}
Run Code Online (Sandbox Code Playgroud)

我的database.php:

'Resources' => array(
                    'driver'    => 'mysql',
                    'host'      => 'localhost',
                    'database'  => 'resources',
                    'username'  => 'user',
                    'password'  => 'password',
                    'charset'   => 'utf8',
                    'collation' => 'utf8_unicode_ci',
                    'prefix'    => '',
            ),

 'mysql' => array(
                    'driver'    => 'mysql',
                    'host'      => 'localhost',
                    'database'  => 'my_data',
                    'username'  => 'user',
                    'password'  => 'password',
                    'charset'   => 'utf8',
                    'collation' => 'utf8_unicode_ci',
                    'prefix'    => '',
            ),
Run Code Online (Sandbox Code Playgroud)

当我试图跑

Album::whereHas('genre', function ($q) {
   $q->where('genre', 'German HopScotch'); 
});
Run Code Online (Sandbox Code Playgroud)

它没有正确选择(不会将数据库名称添加到表"genres"):

Next exception 'Illuminate\Database\QueryException' with message 'SQLSTATE[42S02]: Base table or view not found: 1146 Table 'my_data.genres' doesn't exist
Run Code Online (Sandbox Code Playgroud)

重要的是要注意这是完美的:

Album::first()->genre;
Run Code Online (Sandbox Code Playgroud)

更新

到目前为止,我发现的最好的方法是使用构建器的"from"方法来专门命名正确的连接.我发现查询中的构建器可以接收"from"

Album::whereHas('genre', function ($q) {
   $q->from('resources.genres')->where('genre', 'German HopScotch'); 
});
Run Code Online (Sandbox Code Playgroud)

这是一个不错的解决方案,但它需要我挖掘数据库php并找到一个很好的方法从关系'genre'获取正确的表和数据库名称.

如果有其他人可以在这个解决方案的基础上进一步发展,我会很感激.

Sab*_*osh 24

laravel v5.7及以上解决方案

class Album extends Eloquent {

   // default connection

   public function genre() {
       return $this->setConnection('Resources')->belongsTo('genre');
   }
...
}

Run Code Online (Sandbox Code Playgroud)

  • 我认为 Laravel 5.7+ 根本不需要 setConnection 。只需确保您**指定两个模型的连接**,否则当您尝试从一个模型访问另一个模型时,如果目标模型未指定连接,它将默认为源模型的连接。 (8认同)
  • 请注意,此解决方案在大多数情况下都有效,但可能会产生一些副作用。如果您在获取关系后更新模型,则会遇到 SQL 问题(在错误的数据库连接上进行更新)。 (5认同)
  • 这不是正确的方法,因为一旦使用该关系,您就会永久更改模型的连接,因此之后您将无法再次保存模型。 (2认同)

NiR*_*iRR 8

这是我自己的解决方案,它对我来说一般都适用,但它很复杂.

我正在使用构建器"from"方法在子查询中正确设置表和数据库.我只需要在里面传递正确的信息.

假设子查询可以像"genres.sample"一样复杂甚至更深(这意味着专辑与流派有关系,并且流派与样本有关系)这是如何

$subQuery = 'genres.samples';
$goDeep = (with (new Album));

$tableBreakdown =  preg_split('/\./', $subQuery); //  = ['genres', 'samples']

// I recurse to find the innermost table $album->genres()->getRelated()->sample()->getRelated()
foreach ($tableBreakdown as $table)
    $goDeep = $goDeep->$table()->getRelated();

// now I have the innermost, get table name and database name

$alternativeConnection =  Config::get("database.connections." . $goDeep->getConnectionName() . ".database"); // should be equal to the correct database name

$tableName = $goDeep->getTable(); // I have to use the table name in the "from" method below

Album::whereHas($subQuery, function ($q) use ($alternativeConnection, $tableName) {
$q->from("$alternativeConnection.$tableName"); 
$q->where(....... yadda yadda);
    });
Run Code Online (Sandbox Code Playgroud)

TL:博士;

Album::whereHas('genres', function ($q) { 
    $q->from('resources.genres')->where(....); 
});
Run Code Online (Sandbox Code Playgroud)


Ale*_*lex 8

这是它对我有用的方式:

在我的 .env 和 config/database.php 中,我定义了我的其他连接 =>如何在 Laravel 中使用多个数据库

我以这种方式更新了我的模型:

class MyOtherDBModel extends Model
{
    protected $table = 'tablename';
    protected $connection = 'mysql2';

    public function __construct(array $attributes = [])
    {
        $this->table = env('DB_DATABASE_2').'.'.$this->table;
        parent::__construct();
    }
}

class MyModel extends Model
{
    public function myOtherModel()
    {
        return $this->belongsTo(MyOtherDBModel::class, 'field', 'field');
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我可以打电话

$query = MyModel::whereHas('myOtherModel');
Run Code Online (Sandbox Code Playgroud)

  • 太棒了@Alex,它的工作原理就像一个魅力,就像使用绝对路径而不是相对路径一样。 (2认同)
  • 在每个模型中定义“protected $connection”就足够了。 (2认同)

amf*_*are 7

看起来Eager Loading会做你想做的事

Album::with(['genre' => function ($q) {
   $q->connection('Resources')
     ->where('genre', 'German HopScotch'); 
}]);
Run Code Online (Sandbox Code Playgroud)


Car*_*bar 6

在流派模型上添加具有默认连接的连接变量:

protected $connection = 'mysql';
Run Code Online (Sandbox Code Playgroud)

由于没有添加这个,我的关系出现了一些问题。


ssi*_*nik 6

以防万一有人到达这里。

当您使用来自不同数据库连接的关系获取数据时,请确保相关表已$connection定义该属性,即使它是默认连接也是如此。

Account模型:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Account extends Model {

    protected $connection = 'different_connection';

    public function verifiedBy()
    {
        return $this->belongsTo(User::class, 'verified_by');
    }
}
Run Code Online (Sandbox Code Playgroud)

User模型:

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable {
    // this one uses the default - `database.default` connection
    public function approved()
    {
        return $this->hasMany(Account::class, 'verified_by');
    }
}
Run Code Online (Sandbox Code Playgroud)

一旦我这样做Account:find($id)->verifiedBy,它就会抛出错误。查看数据库名称就可以发现。但如果您这样做,User::find($id)->approved它将正常工作,因为Account模型已定义连接。反之则不然。

因此,为了安全起见,如果您处理多个数据库连接,请将$connection属性放入模型中。

Laravel 的实现


Man*_*anu 5

您应该先克隆,否则您将更改模型的默认连接。它会产生副作用。

class Album extends Eloquent {
    public function genre() {
        $newResource = clone $this;
        return $newResource->setConnection('Resources')->belongsTo('genre');
    }
}
Run Code Online (Sandbox Code Playgroud)