简体   繁体   English

Laravel Eloquent 在不同的连接上预先加载

[英]Laravel Eloquent eager loading on a different connection

I am trying to use Laravel Eloquent ORM to do a simple one to one relationship on two different connections.我正在尝试使用 Laravel Eloquent ORM 在两个不同的连接上建立简单的一对一关系。

Let say I do :假设我这样做:

MyModel::on('secondary_connection')->get()

That is working fine.那工作正常。

When I do :当我做 :

MyModel::on('secondary_connection')->with('AnotherModel')->get();

I am getting an error because eloquent is doing the AnotherModel SELECT statement on the default connection (instead of "secondary_connection").我收到一个错误,因为 eloquent 正在对默认连接(而不是“secondary_connection”)执行 AnotherModel SELECT 语句。

I can't find a way to work this around.我找不到解决此问题的方法。

My models are well defined since I can join them in my default connection.我的模型定义明确,因为我可以在我的默认连接中加入它们。

Thoughts ?想法?

Well, as I've been suggested by many users, it seems that there's no way to do this on the fly.好吧,正如许多用户所建议的那样,似乎没有办法即时执行此操作。 My understanding of this is that Eloquent is incomplete when comes to manage multi-connection.我的理解是 Eloquent 在管理多连接方面是不完整的。

There's 2 way to work this around I could figure.我能想到有两种方法可以解决这个问题。

First, specify the connection in the model :首先,在模型中指定连接:

class MyModel {
    $protected connection = 'secondary_connection';
}

That is obviously a bad workaround since this model is only usable in one connection... but still works.这显然是一个糟糕的解决方法,因为这个模型只能在一个连接中使用……但仍然有效。

Then, as Jarek Tkaczyk suggested, it is possible to switch de default connection with the new one.然后,正如 Jarek Tkaczyk 建议的那样,可以将默认连接切换为新连接。 But instead of doing it in the config file, it is possible to swap the PDO oject.但不是在配置文件中执行此操作,而是可以交换 PDO 对象。

    $default = DB::getPdo(); // Default conn
    $secondary = DB::connection('secondary_connection')->getPdo();
    DB::setPdo($secondary);
    $result = MyModel::with('AnotherModel')->get();
    DB::setPdo($default);

That is a workaround that works and can be a clean solution.这是一种有效的解决方法,并且可以是一个干净的解决方案。 Next step is to put that switching mechanism in a nice Laravel way.下一步是把这个切换机制放在一个很好的 Laravel 方式中。

There's literally no way to do it on the fly.几乎没有办法在飞行中做到这一点。

You need to alter the default connection in order to make Eloquent use it for the eager loaded models.您需要更改默认连接,以便 Eloquent 将其用于预先加载的模型。 You can wrap it in a helper method like this:您可以将其包装在这样的辅助方法中:

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;
}

then just call like below:然后就像下面这样调用:

$models = on('secondary_connection', function () {
   return MyModel::with('relation')->get();
});

I ended up with replacing the simply relationship functions with a bit more custom onces.我最终用更多的自定义函数替换了简单的关系函数。 For instance my ->relatedModel is somewhat of a copy of the original in the Eloquent Model, but includes setting the connection:例如,我的->relatedModel是 Eloquent 模型中原始模型的副本,但包括设置连接:

public function relatedModel() {
  $instance = new \relatedModel;
  $instance->setConnection($this->getConnectionName());
  $query = $instance->newQuery();

  return new BelongsTo($query, $this, 'myForeignKey', $instance->getKeyName(), null);
}

I'm on Laravel 5, so maybe this is different to 4.2.我在 Laravel 5 上,所以这可能与 4.2 不同。

And since I was fiddling around with this issue a lot now here is a great way to get Validation done over another connection than the default: http://laravel.io/forum/10-29-2014-validation-rules-and-multiple-db-connections而且由于我现在经常摆弄这个问题,这是通过默认连接以外的另一个连接完成验证的好方法: http : //laravel.io/forum/10-29-2014-validation-rules-and-多数据库连接

If it is a model method, you can even shorten it down to:如果是模型方法,您甚至可以将其缩短为:

$v = Validator::make($data, $rules);
$v->getPresenceVerifier()->setConnection($this->getConnectionName());

I also am dealing with this issue.我也在处理这个问题。 I found a solution but it will only work if it is acceptable to configure the used connection through the .env file.我找到了一个解决方案,但它只有在可以通过 .env 文件配置使用的连接时才有效。 This will not work if you want to change it dynamically although you could in that case use a bit of logic (call a function) to return the correct connection name.如果您想动态更改它,这将不起作用,尽管在这种情况下您可以使用一些逻辑(调用函数)来返回正确的连接名称。

The solution I have is to override the connectionName method of the Model class.我的解决方案是覆盖 Model 类的 connectionName 方法。 In my case I have a base class for all my models that takes care of this:在我的情况下,我的所有模型都有一个基类来处理这个问题:

abstract class ModelBase extends Model
{
    public function getConnectionName()
    {
        return env('ELOQUENT_DB_CONNECTION', parent::getConnectionName());
    }
}

As I mentioned you can put whatever logic you want in the getConnectionName so you can make it more dynamic.正如我所提到的,您可以在 getConnectionName 中放入任何您想要的逻辑,这样您就可以使其更具动态性。

class MyModel {
    $protected connection = 'secondary_connection';
}

is the nice option as eloquent models are DB facades + extras.是一个不错的选择,因为雄辩的模型是 DB Facades + extras。 all DB facades functions also apply to eloquent models.所有 DB Facades 功能也适用于 eloquent 模型。 therefore instead of changing connection in db facade we can change it here only there is no difference.因此,我们可以在这里更改它而不是更改 db 外观中的连接,只是没有区别。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM