简体   繁体   English

Laravel 联合中的关系冲突

[英]Laravel relationship conflicts in union

I have following model: 1- User model我有以下 model:1-用户 model

 /**
 * 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();
}

and Business model:和业务 model:

 /**
 * Define business and user functional area relationship
 */
public function functionalAreas()
{
    return $this->belongsToMany('App\FunctionalArea', 'business_functional_areas', 'business_id', 'functional_area_id')->withTimestamps();
}

Now I should take all businesses and users and show them in a single list, for this I'm using from union, following is my query:现在我应该将所有企业和用户显示在一个列表中,为此我从联合中使用,以下是我的查询:

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;
} 

But above query not return the business functional area, its output query use from user relationship instead of business, that with section generate twice the following query:但是上面的查询没有返回业务功能区,它的output查询是从用户关系而不是业务中使用的, with section会生成两次如下查询:

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)

But in fact 6, and 7 is business id not user only 2 is user id, one of this queries should use business_functional_areas instead of user_functional_areas .但实际上 6 和 7 是业务 id 而不是用户只有 2 是用户 id,其中一个查询应该使用business_functional_areas而不是user_functional_areas One more thing found is, all items are inside App\User model in result, its like businesses are also as user object.再发现一件事,结果中所有项目都在App\User model 中,其类似的businesses也为用户 object。

In simple words, for now you would not be able to achieve it using Eloquent Eager Loading with Unions .简而言之,目前您无法使用Eloquent Eager Loading with Unions来实现它。 This is not supported yet in Laravel. Laravel 尚不支持此功能。 One of such scenario for which they closed as a Non-Fix issue is Union with Eloquent fail... .他们作为Non-Fix问题关闭的其中一种情况是Union with Eloquent fail...。

Reason : While calling UNION function only the first model( user ) is considered main model and model type of result set of other model( Business ) passed as argument will be converted to the main one( USER ) only and the main model relationship is called on all records(not the desired one). Reason : While calling UNION function only the first model( user ) is considered main model and model type of result set of other model( Business ) passed as argument will be converted to the main one( USER ) only and the main model relationship is called在所有记录上(不是所需的记录)。

Due to the above issue only relationship of user model is called on each record of result set.由于上述问题,仅在结果集的每条记录上调用user model 的关系。 So even for business_id = 1, functional_area of user_id =1 are being fetched.所以即使business_id = 1,user_id = 1 的functional_area 也会被获取。

You can debug more about it from below file & function.您可以从下面的文件和 function 中调试更多信息。

File: 
<your_laravel_project>\vendor\laravel\framework\src\Illuminate\Database\Query\Builder.php
Function: get

Alternate Solution You can fetch the both result set as it is and then merge them after data fetch using php.替代解决方案您可以按原样获取两个结果集,然后在使用 php 获取数据后将它们合并。

public function usersAndOrganizations()
{
    $users = $this->users()->get();
    $organizations = $this->organizations()->get();
    $invitees =  $users->toBase()->merge($organizations->toBase())->toArray();
    dd($invitees);
}

The only way for now is to use from map .目前唯一的方法是使用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;
}

And remove with from your functions, and call this after you get the paginated result.并从你的函数中删除with并在你得到分页结果后调用它。

You can not concat incompatible queries with union.您不能使用联合连接不兼容的查询。 See Unions .请参阅工会
Your users() method return eloquent builder for User entity.您的users()方法返回User实体的 eloquent 构建器。 And organizations() return builder for Business entity.并且organizations()返回Business实体的构建器。
Thus, it is incorrect to select users and organizations in one query.因此,一次查询对 select 用户和组织不正确。
The correct query is like that:正确的查询是这样的:

SELECT City FROM Customers
UNION
SELECT City FROM Suppliers
ORDER BY City;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM