framework: [Eloquent] Relations doesn't use connection of parent model.

I try to get models with their relation from connection, which is chosen dynamically:

User::on('another-db')->with('article')->get();

Unfortunately, instance of related model, which is created in the Model::hasMany() function does not contain this connection.

Solution is to modify function as follows:

public function hasMany($related, $foreignKey = null, $localKey = null)
{
    $foreignKey = $foreignKey ?: $this->getForeignKey();

    $instance = new $related;

    // FIX
    if ($instance->getConnection() == null)  {
        $instance->setConnection($this->connection);
    }

    $localKey = $localKey ?: $this->getKeyName();

    return new HasMany($instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey);
 }

This solution may be used also in belongsTo(), belongsToMany(), etc.

I can create the pull request, but I think this solution may be undesirable if the user wants to define the relation between the parent model from another-db connection and the related model from default connection. This solution override a default connection in related model.

However, I believe that relations between models from the same database are more likely than relations between models from different databases.

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 1
  • Comments: 30 (9 by maintainers)

Most upvoted comments

Why is it closed without a solution? Model relationships aren’t inheriting parent’s connections, we aren’t able to set a connection for them neither

For those who still has this problem:

function relation(){
   $foreignKey = 'fKey';
   $localKey  = 'lKey';

   $instance = new Model();
   $instance->setConnection($this->getConnectionName());

  return new HasOne($instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey);
}

I hope it helps!

This is already implemented on L5.4, although I think it should be optional by setting something like protected $inheritConnection = true; because its annoying to handle some times.

Or better yet, I like reno1979’s idea of App\myModel::on('mysql2', true); /* True for propegate connection */

Currently every model sets its own connection and there’s no way to force the parent connection, I’m checking with Taylor if adding such functionality would be a good idea.

I did a completely unorthodox way, I needed an extremely urgent fix, and since this hasn’t been updated for 2 years I just added this line in the Model.php on all the relationship functions:

$instance = new $related;
$instance->setConnection($this->getConnectionName());

And it just works as expected absolutely everywhere, if there is no connection overload, it just uses the default one and that’s it.

I think it should be the official fix, but until then I had to commit the Laravel framework folder to my repository, and lock the version in composer.

I hope an official fix will soon arise so I don’t have to do these kinds of blasphemy.

Sorry to revive a crazy old issue but this still happens in laravel 5.8-7.x.

I’ve found a possible solution which involves overwriting Illuminate/Database/Eloquent/Concerns/HasRelationships.php newRelatedInstance() method. This can be done in your base model and seems fairly easy. https://github.com/laravel/ideas/issues/2326

@avasa I didn’t read everything yet, but do you use the most recent laravel version? Much things are already fixed…

@GrahamCampbell @taylorotwell @themsaid @BartHuis

Could this issue please be reopend? I’ve encounter multiple issues this week, all caused by this underlying mecanism/issue.

I ‘solved’ it with changing the default database connection and restoring it, but this is going to introduce unwanted effects eventually.

Adding this ‘fix’ to relations in a own made model should work:

$instance = new $related;
$instance->setConnection($this->getConnectionName());

When a Laravel extension (which creates relations in your Models etc) is used, this extension should also apply this ‘fix’. 😦

But a real solution would be much nicer. I saw a proposal for a propegateConnection by @davisonja Something like that could work. Or similar:

App\myModel::on('mysql2', true); /* True for propegate connection */

I also encountered this issue in 5.3.19 😦

I hope there will be a real fix for this