ira*_*ira 6 mysql eager-loading relationships laravel eloquent
我处理以下情况:我有两个型号,一个Employee具有id和name字段和Telephone用id,employee_id和flag领域.这两种模式之间也存在一对多关系,即员工可能拥有多部电话,而电话可能属于一名员工.
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 = []
考虑到这篇文章、这篇文章和@Giedrius Kir\xc5\xa1ys 下面的答案,我最终想出了一个适合我的需求的解决方案,使用以下步骤:
\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}\nRun Code Online (Sandbox Code Playgroud)\n\n在控制器中
\n\n现在我可以使用这个优雅的语法 a\xe2\x80\x99la Eloquent
\n\n$employees = Employee::with(\'flaggedTelephones\')->hasFlaggedTelephones()->get();\nRun Code Online (Sandbox Code Playgroud)\n\n其内容类似于“获取所有带有已标记电话的员工,然后只获取至少拥有一部标记电话的员工”
\n\n编辑:
\n\n在处理 Laravel 框架一段时间后(当前版本使用 5.2.39),我想,事实上,whereHas()如果关系模型存在于不同的数据库中,则子句确实可以使用from(),如下所示:
$employees = Employee::whereHas(\'telephones\', function($query){\n\n $query->from(\'mydb2.telephones\')->where(\'flag\', 1);\n\n})->get();\nRun Code Online (Sandbox Code Playgroud)\n\n@Rob Contreras 赞扬了该方法的使用from(),但看起来该方法需要将数据库和表作为参数。