我正在处理以下情况:我有两个模型,Employee
id
和name
字段以及Telephone
id
,{ {1}}和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);
}
}
模型引用名为Employee
的数据库模式中存在的表employees
,而mydb1
模型与存在的Telephone
表相关在名为telephones
的其他数据库模式中。
我想要的是使用Eloquent 仅使用至少一个特定标志渴望加载的电话来员工和(如果可能)不是查询构建器
到目前为止我尝试的没有成功是:
1)使用Controller中的whereHas方法
mydb2
我在这里尝试的方法是首先只检索拥有flag = 1的电话的员工,然后只搜索那些只打算加载这些电话的员工,但我得到以下查询异常因为不同使用的数据库连接:
找不到基表或视图:表mydb1.telephones不存在(这是真的,mydb2中存在电话)
2)在控制器
中使用约束进行预加载$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();
这种方法急切地加载了flag = 1的电话,但它返回所有员工实例,这不是我真正想要的。我想收集只有具有$employees = Employee::with([
'telephones' => function ($query) {
$query->where('flag', 1);
},
])->get();
= 1的电话的员工模型,不包括flag
的模型
答案 0 :(得分:2)
考虑到this post,this post和@GiedriusKiršys的回答,我终于想出了一个符合我需求的解决方案,使用以下步骤:
员工模型
/**
* This is the new relationship
*
*/
public function flaggedTelephones()
{
return $this->telephones()
->where('flag', 1); //this will return a relation object
}
/**
* This is the query scope that filters the flagged telephones
*
* This is the raw query performed:
* select * from mydb1.employees where exists (
* select * from mydb2.telephones
* where telephones.employee_id = employee.id
* and flag = 1);
*
*/
public function scopeHasFlaggedTelephones($query, $id)
{
return $query->whereExists(function ($query) use ($id) {
$query->select(DB::raw('*'))
->from('mydb2.telephones')
->where('telephones.flag', $flag)
->whereRaw('telephones.employee_id = employees.id');
});
}
在控制器
中现在我可以使用这种优雅的语法a'la Eloquent
$employees = Employee::with('flaggedTelephones')->hasFlaggedTelephones()->get();
读起来像“抓住所有带有标记电话的员工急切加载,然后只接受至少有一个标记电话的员工”
修改强>
在处理Laravel框架一段时间后(当前版本使用5.2.39),我想,事实上,whereHas()
子句在关系模型存在于使用{的不同数据库的情况下工作{1}}方法,如下所示:
from()
@Rob Contreras声明使用$employees = Employee::whereHas('telephones', function($query){
$query->from('mydb2.telephones')->where('flag', 1);
})->get();
方法,但看起来该方法需要将数据库和表作为参数。
答案 1 :(得分:1)
不确定这是否有效,但您可以使用from方法在闭包中指定数据库连接:
$employees = Employee::whereHas('telephones', function($query){
$query->from('mydb2')->where('flag', 1);
})->get();
希望这有帮助
答案 2 :(得分:1)
肮脏的解决方案:
使用whereExists
和范围以提高可读性。
在您的Employee
模型中:
public function scopeFlags($query, $flag)
{
$query->whereExists(function ($q) use ($flag) {
$q->select(\DB::raw(1))
->from('mydb2.telephones')
->where('telephones.flag', $flag)
->whereRaw('telephones.employee_id = employees.id');
});
}
然后像这样修改您的查询:
$employees = Employee::flags(1)->get();