Laravel Eloquent 在不同的连接上预先加载
Laravel Eloquent eager loading on a different connection
我正在尝试使用 Laravel Eloquent ORM 在两个不同的连接上建立简单的一对一关系。
假设我愿意:
MyModel::on('secondary_connection')->get()
工作正常。
当我这样做时:
MyModel::on('secondary_connection')->with('AnotherModel')->get();
我收到一个错误,因为 eloquent 正在默认连接上执行 AnotherModel SELECT 语句(而不是“secondary_connection”)。
我找不到解决这个问题的方法。
我的模型定义明确,因为我可以在我的默认连接中加入它们。
想法?
几乎没有办法即时完成。
您需要更改默认连接,以便 Eloquent 将其用于预先加载的模型。您可以将其包装在这样的辅助方法中:
function on($connection, Closure $callback)
{
// backup default connection
$default = Config::get('database.default');
// change for current query
Config::set('database.default', $connection);
// run the query
$result = $callback();
// restore the default connection
Config::set('database.default', $default);
return $result;
}
然后像下面这样调用:
$models = on('secondary_connection', function () {
return MyModel::with('relation')->get();
});
好吧,正如许多用户所建议的那样,似乎没有办法即时执行此操作。我对此的理解是Eloquent在管理多连接时是不完整的。
我想出了 2 种方法来解决这个问题。
首先,在模型中指定连接:
class MyModel {
$protected connection = 'secondary_connection';
}
这显然是一个糟糕的解决方法,因为该模型只能在一个连接中使用...但仍然有效。
然后,正如 Jarek Tkaczyk 所建议的,可以将默认连接切换为新连接。但是不是在配置文件中做,而是可以交换 PDO 对象。
$default = DB::getPdo(); // Default conn
$secondary = DB::connection('secondary_connection')->getPdo();
DB::setPdo($secondary);
$result = MyModel::with('AnotherModel')->get();
DB::setPdo($default);
这是一种有效的解决方法,可以是一个干净的解决方案。下一步是以一种很好的 Laravel 方式放置该切换机制。
我最终用更多的自定义 onces 替换了简单的关系函数。例如,我的 ->relatedModel
有点像 Eloquent 模型中原始模型的副本,但包括设置连接:
public function relatedModel() {
$instance = new \relatedModel;
$instance->setConnection($this->getConnectionName());
$query = $instance->newQuery();
return new BelongsTo($query, $this, 'myForeignKey', $instance->getKeyName(), null);
}
我在 Laravel 5,所以这可能与 4.2 不同。
而且由于我经常摆弄这个问题,现在这里是通过另一个连接而不是默认连接完成验证的好方法:http://laravel.io/forum/10-29-2014-validation-rules-and-multiple-db-connections
如果是模型方法,甚至可以缩短为:
$v = Validator::make($data, $rules);
$v->getPresenceVerifier()->setConnection($this->getConnectionName());
我也在处理这个问题。我找到了一个解决方案,但只有在可以接受通过 .env 文件配置使用的连接时它才会起作用。如果您想动态更改它,这将不起作用,尽管在这种情况下您可以使用一些逻辑(调用函数)来 return 正确的连接名称。
我的解决方案是重写模型的 connectionName 方法 class。在我的例子中,我的所有模型都有一个基础 class 来处理这个问题:
abstract class ModelBase extends Model
{
public function getConnectionName()
{
return env('ELOQUENT_DB_CONNECTION', parent::getConnectionName());
}
}
正如我提到的,您可以在 getConnectionName 中放置任何您想要的逻辑,这样您就可以使其更加动态。
class MyModel {
$protected connection = 'secondary_connection';
}
是不错的选择,因为 eloquent 模型是 DB facades + extras。所有 DB facades 函数也适用于 eloquent 模型。因此,我们可以在这里更改它,而不是更改 db facade 中的连接,只是没有区别。
我正在尝试使用 Laravel Eloquent ORM 在两个不同的连接上建立简单的一对一关系。
假设我愿意:
MyModel::on('secondary_connection')->get()
工作正常。
当我这样做时:
MyModel::on('secondary_connection')->with('AnotherModel')->get();
我收到一个错误,因为 eloquent 正在默认连接上执行 AnotherModel SELECT 语句(而不是“secondary_connection”)。
我找不到解决这个问题的方法。
我的模型定义明确,因为我可以在我的默认连接中加入它们。
想法?
几乎没有办法即时完成。
您需要更改默认连接,以便 Eloquent 将其用于预先加载的模型。您可以将其包装在这样的辅助方法中:
function on($connection, Closure $callback)
{
// backup default connection
$default = Config::get('database.default');
// change for current query
Config::set('database.default', $connection);
// run the query
$result = $callback();
// restore the default connection
Config::set('database.default', $default);
return $result;
}
然后像下面这样调用:
$models = on('secondary_connection', function () {
return MyModel::with('relation')->get();
});
好吧,正如许多用户所建议的那样,似乎没有办法即时执行此操作。我对此的理解是Eloquent在管理多连接时是不完整的。
我想出了 2 种方法来解决这个问题。
首先,在模型中指定连接:
class MyModel {
$protected connection = 'secondary_connection';
}
这显然是一个糟糕的解决方法,因为该模型只能在一个连接中使用...但仍然有效。
然后,正如 Jarek Tkaczyk 所建议的,可以将默认连接切换为新连接。但是不是在配置文件中做,而是可以交换 PDO 对象。
$default = DB::getPdo(); // Default conn
$secondary = DB::connection('secondary_connection')->getPdo();
DB::setPdo($secondary);
$result = MyModel::with('AnotherModel')->get();
DB::setPdo($default);
这是一种有效的解决方法,可以是一个干净的解决方案。下一步是以一种很好的 Laravel 方式放置该切换机制。
我最终用更多的自定义 onces 替换了简单的关系函数。例如,我的 ->relatedModel
有点像 Eloquent 模型中原始模型的副本,但包括设置连接:
public function relatedModel() {
$instance = new \relatedModel;
$instance->setConnection($this->getConnectionName());
$query = $instance->newQuery();
return new BelongsTo($query, $this, 'myForeignKey', $instance->getKeyName(), null);
}
我在 Laravel 5,所以这可能与 4.2 不同。
而且由于我经常摆弄这个问题,现在这里是通过另一个连接而不是默认连接完成验证的好方法:http://laravel.io/forum/10-29-2014-validation-rules-and-multiple-db-connections
如果是模型方法,甚至可以缩短为:
$v = Validator::make($data, $rules);
$v->getPresenceVerifier()->setConnection($this->getConnectionName());
我也在处理这个问题。我找到了一个解决方案,但只有在可以接受通过 .env 文件配置使用的连接时它才会起作用。如果您想动态更改它,这将不起作用,尽管在这种情况下您可以使用一些逻辑(调用函数)来 return 正确的连接名称。
我的解决方案是重写模型的 connectionName 方法 class。在我的例子中,我的所有模型都有一个基础 class 来处理这个问题:
abstract class ModelBase extends Model
{
public function getConnectionName()
{
return env('ELOQUENT_DB_CONNECTION', parent::getConnectionName());
}
}
正如我提到的,您可以在 getConnectionName 中放置任何您想要的逻辑,这样您就可以使其更加动态。
class MyModel {
$protected connection = 'secondary_connection';
}
是不错的选择,因为 eloquent 模型是 DB facades + extras。所有 DB facades 函数也适用于 eloquent 模型。因此,我们可以在这里更改它,而不是更改 db facade 中的连接,只是没有区别。