Laravel 联合中的关系冲突
Laravel relationship conflicts in union
我有以下型号:
1- 用户模型
/**
* Define user and functional area relationship
*/
public function functionalAreas()
{
return $this->belongsToMany('App\FunctionalArea', 'user_functional_areas', 'user_id', 'functional_area_id')->withPivot('id', 'is_primary')->withTimestamps();
}
和商业模式:
/**
* Define business and user functional area relationship
*/
public function functionalAreas()
{
return $this->belongsToMany('App\FunctionalArea', 'business_functional_areas', 'business_id', 'functional_area_id')->withTimestamps();
}
现在我应该把所有的企业和用户都显示在一个列表中,为此我使用的是 union,下面是我的查询:
public function usersAndOrganizations()
{
$users = $this->users();
$organizations = $this->organizations();
$invitees = $users->union($organizations)->paginate(10);
return response()->json($invitees);
}
private function users()
{
$users = User::byState($approved = true, 'is_approved')
->search()->select([
'id',
DB::raw("CONCAT(first_name, ' ', last_name) AS name"),
'about',
'address',
'slug',
'average_reviews',
DB::raw("'freelancer' AS type")
]);
$users = $users->with([
"functionalAreas" => function ($q) {
$q->select([
'functional_areas.id',
DB::raw("functional_areas.name_en AS name"),
]);
}
]);
return $users;
}
private function organizations()
{
$businesses = Business::where('owner_id', '!=', auth()->user()->id)->verified()
->active()->search()
->select([
'id',
'name',
'about',
'address',
'slug',
'average_reviews',
DB::raw("'business' AS type")
]);
$businesses = $businesses
->with([
"functionalAreas" => function ($q) {
$q->select([
'functional_areas.id',
DB::raw("functional_areas.name_en AS name"),
]);
}
]);
return $businesses;
}
但是上面的查询不是return业务功能区,它的输出查询使用的是用户关系而不是业务,with
部分会生成两次以下查询:
select
`functional_areas`.`id`,
functional_areas.name_en AS name,
`user_functional_areas`.`user_id` as `pivot_user_id`,
`user_functional_areas`.`functional_area_id` as `pivot_functional_area_id`,
`user_functional_areas`.`id` as `pivot_id`,
`user_functional_areas`.`is_primary` as `pivot_is_primary`,
`user_functional_areas`.`created_at` as `pivot_created_at`,
`user_functional_areas`.`updated_at` as `pivot_updated_at`
from `functional_areas`
inner join `user_functional_areas`
on `functional_areas`.`id` = `user_functional_areas`.`functional_area_id`
where `user_functional_areas`.`user_id` in (2, 6, 7)
但实际上6和7是business id不是user only 2是user id,其中一个查询应该使用business_functional_areas
而不是user_functional_areas
。
发现的另一件事是,结果中所有项目都在 App\User
模型内,它的 businesses
也是用户对象。
您不能使用并集连接不兼容的查询。
参见 Unions。
您的 users()
方法 return eloquent 构建器用于 User
实体。
organizations()
return Business
实体的生成器。
因此,在一个查询中 select 用户和组织是不正确的。
正确的查询是这样的:
SELECT City FROM Customers
UNION
SELECT City FROM Suppliers
ORDER BY City;
简而言之,目前您无法使用 Eloquent Eager Loading
和 Unions
来实现它。 Laravel 尚不支持此功能。他们作为 Non-Fix
问题关闭的此类情况之一是 Union with Eloquent fail....
原因:调用UNION
函数时,只有第一个模型(user
)被认为是主模型和其他模型结果集的模型类型( Business
) 作为参数传递的将仅转换为主模型关系 (USER
) 并且在所有记录(不是所需的记录)上调用主模型关系。
由于上述问题,仅在结果集的每条记录上调用 user
模型的关系。因此,即使 business_id = 1,functional_area of user_id =1 正在被提取。
您可以从下面的文件和函数中调试更多信息。
File:
<your_laravel_project>\vendor\laravel\framework\src\Illuminate\Database\Query\Builder.php
Function: get
备用解决方案
您可以按原样获取两个结果集,然后在使用 php.
获取数据后合并它们
public function usersAndOrganizations()
{
$users = $this->users()->get();
$organizations = $this->organizations()->get();
$invitees = $users->toBase()->merge($organizations->toBase())->toArray();
dd($invitees);
}
目前唯一的方法是使用 from map
.
public function usersAndOrganizations()
{
$users = $this->users();
$organizations = $this->organizations();
$invitees = $users->union($organizations)->paginate(10);
$invitees = $this->getRelatedData($invitees);
return response()->json($invitees);
}
private function getRelatedData($invitees)
{
$invitees->map(function($object) use($functionalAreaName) {
if($object->type == 'business') {
$relationName = 'businesses';
$relationKey = 'business_id';
$attachableType = Business::MORPHABLE_TYPE;
}
if($object->type == 'freelancer') {
$relationName = 'users';
$relationKey = 'user_id';
$attachableType = User::MORPHABLE_TYPE;
}
$functionalAreas = FunctionalArea::whereHas($relationName, function($q) use ($object, $relationKey){
$q->where($relationKey, $object->id);
})->get([$functionalAreaName.' As name', 'id']);
$object->functional_areas = $functionalAreas->toArray();
});
return $invitees;
}
并从您的函数中删除 with
,并在获得分页结果后调用它。
我有以下型号: 1- 用户模型
/**
* Define user and functional area relationship
*/
public function functionalAreas()
{
return $this->belongsToMany('App\FunctionalArea', 'user_functional_areas', 'user_id', 'functional_area_id')->withPivot('id', 'is_primary')->withTimestamps();
}
和商业模式:
/**
* Define business and user functional area relationship
*/
public function functionalAreas()
{
return $this->belongsToMany('App\FunctionalArea', 'business_functional_areas', 'business_id', 'functional_area_id')->withTimestamps();
}
现在我应该把所有的企业和用户都显示在一个列表中,为此我使用的是 union,下面是我的查询:
public function usersAndOrganizations()
{
$users = $this->users();
$organizations = $this->organizations();
$invitees = $users->union($organizations)->paginate(10);
return response()->json($invitees);
}
private function users()
{
$users = User::byState($approved = true, 'is_approved')
->search()->select([
'id',
DB::raw("CONCAT(first_name, ' ', last_name) AS name"),
'about',
'address',
'slug',
'average_reviews',
DB::raw("'freelancer' AS type")
]);
$users = $users->with([
"functionalAreas" => function ($q) {
$q->select([
'functional_areas.id',
DB::raw("functional_areas.name_en AS name"),
]);
}
]);
return $users;
}
private function organizations()
{
$businesses = Business::where('owner_id', '!=', auth()->user()->id)->verified()
->active()->search()
->select([
'id',
'name',
'about',
'address',
'slug',
'average_reviews',
DB::raw("'business' AS type")
]);
$businesses = $businesses
->with([
"functionalAreas" => function ($q) {
$q->select([
'functional_areas.id',
DB::raw("functional_areas.name_en AS name"),
]);
}
]);
return $businesses;
}
但是上面的查询不是return业务功能区,它的输出查询使用的是用户关系而不是业务,with
部分会生成两次以下查询:
select
`functional_areas`.`id`,
functional_areas.name_en AS name,
`user_functional_areas`.`user_id` as `pivot_user_id`,
`user_functional_areas`.`functional_area_id` as `pivot_functional_area_id`,
`user_functional_areas`.`id` as `pivot_id`,
`user_functional_areas`.`is_primary` as `pivot_is_primary`,
`user_functional_areas`.`created_at` as `pivot_created_at`,
`user_functional_areas`.`updated_at` as `pivot_updated_at`
from `functional_areas`
inner join `user_functional_areas`
on `functional_areas`.`id` = `user_functional_areas`.`functional_area_id`
where `user_functional_areas`.`user_id` in (2, 6, 7)
但实际上6和7是business id不是user only 2是user id,其中一个查询应该使用business_functional_areas
而不是user_functional_areas
。
发现的另一件事是,结果中所有项目都在 App\User
模型内,它的 businesses
也是用户对象。
您不能使用并集连接不兼容的查询。
参见 Unions。
您的 users()
方法 return eloquent 构建器用于 User
实体。
organizations()
return Business
实体的生成器。
因此,在一个查询中 select 用户和组织是不正确的。
正确的查询是这样的:
SELECT City FROM Customers
UNION
SELECT City FROM Suppliers
ORDER BY City;
简而言之,目前您无法使用 Eloquent Eager Loading
和 Unions
来实现它。 Laravel 尚不支持此功能。他们作为 Non-Fix
问题关闭的此类情况之一是 Union with Eloquent fail....
原因:调用UNION
函数时,只有第一个模型(user
)被认为是主模型和其他模型结果集的模型类型( Business
) 作为参数传递的将仅转换为主模型关系 (USER
) 并且在所有记录(不是所需的记录)上调用主模型关系。
由于上述问题,仅在结果集的每条记录上调用 user
模型的关系。因此,即使 business_id = 1,functional_area of user_id =1 正在被提取。
您可以从下面的文件和函数中调试更多信息。
File:
<your_laravel_project>\vendor\laravel\framework\src\Illuminate\Database\Query\Builder.php
Function: get
备用解决方案 您可以按原样获取两个结果集,然后在使用 php.
获取数据后合并它们public function usersAndOrganizations()
{
$users = $this->users()->get();
$organizations = $this->organizations()->get();
$invitees = $users->toBase()->merge($organizations->toBase())->toArray();
dd($invitees);
}
目前唯一的方法是使用 from map
.
public function usersAndOrganizations()
{
$users = $this->users();
$organizations = $this->organizations();
$invitees = $users->union($organizations)->paginate(10);
$invitees = $this->getRelatedData($invitees);
return response()->json($invitees);
}
private function getRelatedData($invitees)
{
$invitees->map(function($object) use($functionalAreaName) {
if($object->type == 'business') {
$relationName = 'businesses';
$relationKey = 'business_id';
$attachableType = Business::MORPHABLE_TYPE;
}
if($object->type == 'freelancer') {
$relationName = 'users';
$relationKey = 'user_id';
$attachableType = User::MORPHABLE_TYPE;
}
$functionalAreas = FunctionalArea::whereHas($relationName, function($q) use ($object, $relationKey){
$q->where($relationKey, $object->id);
})->get([$functionalAreaName.' As name', 'id']);
$object->functional_areas = $functionalAreas->toArray();
});
return $invitees;
}
并从您的函数中删除 with
,并在获得分页结果后调用它。