我可以在laravel查询构建器中一起使用`join`和`with`吗?

时间:2017-02-10 18:41:45

标签: php mysql laravel relational-database

我有users表,每个用户都可以拥有很多技能:

 $user = User::with('Skill')->where('id',1)->first();

到目前为止没问题!我可以使用这样的技能:

$user->Skill->name

还有许多其他表属于用户,例如(公司,颜色......)我想在我的控制器中使用它们一次,所以我不想在用户模型中创建关系函数

我想要的是这样的查询:

$user = User::with('Skill')
            ->leftJoin('companies', function ($join) use ($id) {
                $join->on('companies.user_id','=' ,'users.id');
                $join->where('users.id', '=',$id);
            })
            ->leftJoin('colors', function ($join) use ($id) {
                $join->on('colors.user_id','=' ,'users.id');
                $join->where('users.id', '=',$id);
            })
            ->first();

但它为我提供了$user信息,其中包含空的个人资料,没有颜色,也没有公司!

我是否必须将Skill模型放入加入而不是with()

1 个答案:

答案 0 :(得分:1)

如果我正确理解您的问题,您可以加载多个关系

App\User::with('skill', 'country', 'color')->first();

以下是修补程序中的示例输出

=> App\User {#666
     id: "1",
     name: "Gussie Rice DVM",
     email: "delfina.treutel@example.org",
     created_at: "2017-02-10 19:09:43",
     updated_at: "2017-02-10 19:09:43",
     skill: App\Skill {#662
       id: "1",
       name: "mollitia",
       user_id: "1",
       created_at: "2017-02-10 19:09:43",
       updated_at: "2017-02-10 19:09:43",
     },
     country: App\Country {#667
       id: "1",
       name: "Sierra Leone",
       user_id: "1",
       created_at: "2017-02-10 19:09:43",
       updated_at: "2017-02-10 19:09:43",
     },
     color: App\Color {#669
       id: "1",
       name: "Brown",
       user_id: "1",
       created_at: "2017-02-10 19:09:43",
       updated_at: "2017-02-10 19:09:43",
     },
   }

在这个例子中,所有关系都是一对一的,但它们很容易就是一对多。

App\User::with('skills', 'countries', 'colors')->first();

<强>更新

  

正如我在问题中所说,我只想在我的控制器中使用它们,所以我不想在用户模型中创建关系函数。 (我必须这样做吗?)......

<强> TL; DR

在这种特殊情况下,您尝试做的事情并没有多大意义,因为它更加冗长,不那么明显,更容易出错,难以维持而不是<强大的>雄辩的惯用法方式,这是User模型中的两个超短非常清晰的关系函数,然后是控制器中的一个单行程序,用于获取用户并加载所有三个关系。

长篇解释

只要在结果集中消除列名歧义,使用with和连接就完全没问题。否则,在创建模型实例时,最右边的非空值将覆盖具有相同名称的列的值。为了澄清你加入三个表(用户 - &gt;公司 - &gt;颜色)并且所有表都有name列的情况,你将获得一个名为User的实例设置为颜色名称,如果它不是null

让我说明一下。如果我们运行您的查询,为了简洁我省略,我们得到以下回复

=> App\User {#871
     id: "1",
     name: "Tomato", // <-- color name instead of the user name
     email: "walter.elyse@example.org",
     created_at: "2017-02-10 19:34:51",
     updated_at: "2017-02-10 19:34:51",
     user_id: "1",
     skill: App\Skill {#873
       id: "1",
       name: "tempora",
       user_id: "1",
       created_at: "2017-02-10 19:34:51",
       updated_at: "2017-02-10 19:34:51",
     },
   }

在返回的User模型中查看如何将名称设置为颜色名称而不是用户名

您需要明确定义雄心勃勃的列的名称:

App\User::with('skill')->leftJoin('companies', function ($join) use ($id) 
    join->on('companies.user_id','=' ,'users.id');
    $join->on('users.id', '=',$id);
})->leftJoin('colors', function ($join) use ($id) {
    $join->on('colors.user_id','=' ,'users.id');
    $join->on('users.id', '=', $id);
})->select(
    'users.*', 
    'companies.name as company_name', // <--
    'colors.name as color_name' // <--
)->first();

哪个会给你

=> App\User {#885
     id: "1",
     name: "Kareem Mante", // <-- users.name
     email: "walter.elyse@example.org",
     created_at: "2017-02-10 19:34:51",
     updated_at: "2017-02-10 19:34:51",
     company_name: "Renner Group", // <- companies.name
     color_name: "Tomato", // <-- colors.name
     skill: App\Skill {#887
       id: "1",
       name: "tempora",
       user_id: "1",
       created_at: "2017-02-10 19:34:51",
       updated_at: "2017-02-10 19:34:51",
     },
   }

现在您可能想要使用联接的唯一情况是,如果您返回一个较大的结果集并希望避免有4个单独的查询(每个模型/表一个)。