在Laravel 5.2中使用多个MySQL数据库连接查询关系存在

ira*_*ira 6 mysql eager-loading relationships laravel eloquent

我处理以下情况:我有两个型号,一个Employee具有idname字段和Telephoneid,employee_idflag领域.这两种模式之间也存在一对多关系,即员工可能拥有多部电话,而电话可能属于一名员工.

class Employee extends Model
{
    public function telephones()
    {
        return $this->hasMany(Telephone::class);
    }
}



class Telephone extends Model
{
        public function employee()
    {
        return $this->belongsTo(Employee::class);
    }
}
Run Code Online (Sandbox Code Playgroud)

Employee模型引用employees存在于名为的数据库模式中的表mydb1,而该Telephone模型与telephones存在于名为的不同数据库模式中的表相关mydb2.

我要的是只获取与员工至少一个电话的特定标志的渴望装,用雄辩和(如果可能)没有查询生成器

到目前为止我没有成功的尝试是:

1)使用Controller中的whereHas方法

$employees = Employee::whereHas('telephones', function ($query) {

    $query->where('flag', 1); //Fetch only the employees with telephones of flag=1

})->with([

    'telephones' => function ($query) { //Eager load only the telephones of flag=1

        $query->where('flag', 1);
    }

])->get();
Run Code Online (Sandbox Code Playgroud)

我在这里尝试做的是首先仅检索具有flag = 1的电话的员工,然后仅仅检索这些电话的急切负载,但由于使用了不同的数据库连接,我得到以下查询异常:

未找到基表或视图:表mydb1.telephones不存在(这是真的,mydb2中存在电话)

2)在控制器中带有约束的急切负载

$employees = Employee::with([

    'telephones' => function ($query) {

        $query->where('flag', 1);
    },

])->get();
Run Code Online (Sandbox Code Playgroud)

这种方法急切地加载了flag = 1的电话,但它返回了所有员工实例,这不是我真正想要的.我想拥有一个只有具有flag= 1的电话的员工模型的集合,不包括带有的模型telephones = []

ira*_*ira 2

考虑到这篇文章这篇文章和@Giedrius Kir\xc5\xa1ys 下面的答案,我最终想出了一个适合我的需求的解决方案,使用以下步骤:

\n\n
    \n
  1. 创建一个返回模型中的Relation 对象的方法
  2. \n
  3. 在控制器中立即加载这个新关系
  4. \n
  5. 使用模型中的查询范围过滤掉 flag != 1 的电话
  6. \n
\n\n

在员工模型中

\n\n
/**\n * This is the new relationship\n *\n */\npublic function flaggedTelephones()\n{\n    return $this->telephones()\n        ->where(\'flag\', 1); //this will return a relation object\n}\n\n\n\n/**\n *  This is the query scope that filters the flagged telephones\n *\n *    This is the raw query performed:\n *    select * from mydb1.employees where exists (\n *    select * from mydb2.telephones\n *    where telephones.employee_id = employee.id\n *    and flag = 1);\n *\n */    \npublic function scopeHasFlaggedTelephones($query, $id)\n{\n    return $query->whereExists(function ($query) use ($id) {\n        $query->select(DB::raw(\'*\'))\n            ->from(\'mydb2.telephones\')\n            ->where(\'telephones.flag\', $flag)\n            ->whereRaw(\'telephones.employee_id = employees.id\');\n    });\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在控制器中

\n\n

现在我可以使用这个优雅的语法 a\xe2\x80\x99la Eloquent

\n\n
$employees = Employee::with(\'flaggedTelephones\')->hasFlaggedTelephones()->get();\n
Run Code Online (Sandbox Code Playgroud)\n\n

其内容类似于“获取所有带有已标记电话的员工,然后只获取至少拥有一部标记电话的员工”

\n\n

编辑:

\n\n

在处理 Laravel 框架一段时间后(当前版本使用 5.2.39),我想,事实上,whereHas()如果关系模型存在于不同的数据库中,则子句确实可以使用from(),如下所示:

\n\n
$employees = Employee::whereHas(\'telephones\', function($query){\n\n    $query->from(\'mydb2.telephones\')->where(\'flag\', 1);\n\n})->get();\n
Run Code Online (Sandbox Code Playgroud)\n\n

@Rob Contreras 赞扬了该方法的使用from(),但看起来该方法需要将数据库和表作为参数。

\n