Laravel 5 leftJoin on belongsTo 关系

Posted

技术标签:

【中文标题】Laravel 5 leftJoin on belongsTo 关系【英文标题】:Laravel 5 leftJoin on belongsTo relation 【发布时间】:2015-01-20 17:44:14 【问题描述】:

我有两个数据库表:用户和学生。学生是用户,但有额外的数据(地址)。我的 Student 模型中有一个 belongsTo('User') 关系。

如果我现在这样查询 Student 模型:

$this->student
    ->with('user')
    ->first();

我得到这个结果:


    "id": 1,
    "user_id": 12,
    "street": "Petershof",
    "house_number": "3787",
    "postal_code": "8161 NM",
    "city": "Tienhoven",
    "user": 
        "id": 12,
        "email": "bvierdag@yahoo.nl",
        "first_name": "Nathan",
        "last_name": "van Dijk",
        "name": "Nathan van Dijk"
    

但是,我想展平结果,以便用户字段位于父(学生)对象中。像这样:


    "id": 1,
    "user_id": 12,
    "street": "Petershof",
    "house_number": "3787",
    "postal_code": "8161 NM",
    "city": "Tienhoven",
    "email": "bvierdag@yahoo.nl",  // = user field
    "first_name": "Nathan",        // = user field
    "last_name": "van Dijk",       // = user field
    "name": "Nathan van Dijk"      // = user field

我尝试使用 leftJoin('users', 'user_id', '=', 'users.id') 而不是 with(),但后来我失去了我的虚拟属性 'name'(在用户模型中定义) ) 也不能再查询用户的关系了。

我怎样才能以干净的方式实现这一目标?

【问题讨论】:

【参考方案1】:
$this->student
  ->leftJoin('users', 'users.id', '=', 'students.user_id')
  ->select(
    'students.*',
    'users.email',
    'users.first_name',
    'users.last_name',
    DB::raw("concat(users.first_name, ' ', users.last_name) as name"),
  )->first();

在这种情况下,您可以像 users.email 一样将表格放入 select 中。

关系将同样起作用,我想问题只是用users id 覆盖students id,如果你没有指定select 而只是抓住了所有的领域。

【讨论】:

感谢您的回答。目前这是一个很好的方法,但我不太喜欢的是你跳过了 User 模型。因此,如果我想更改虚拟名称字段,我必须在不同的位置进行更改。 跳过用户模型是什么意思?如果您想要实现的唯一目标是输出表示,我想以 JSON 的形式,那么您应该这么说。 我的意思是使用 leftJoin() 我必须将“虚拟名称字段”重写为 sql concat,而我已经在 User 模型中定义了它,所以这是双代码而不是 DRY。理想情况下会做这样的事情:$this->student->with(user, 'left join')->first()。有没有办法做到这一点? 好吧,在这种情况下我不会担心 DRY。您要么使用 Eloquent 及其所有功能(即,在关系上根本没有 joins),要么使用自定义查询(如我上面所示)。所以,不,没有办法做到这一点。再说一遍,告诉我你想要什么,然后我可以提出解决方案。 好的,谢谢您的解释。我想创建一个 JSON api。未来还会有更复杂的关系,所以你有什么建议?使用 Eloquent、自定义 sql 或其他 ORM?【参考方案2】:

老问题,但这里有。

阅读您的评论,您似乎想为此制作一个 api。如果只有一个端点在运行中格式化结果应该不是问题,但是对于更多端点,我建议使用转换器模式。

这可以通过让一个单独的类根据您的数据库数据返回一个数组来实现。然后你把那个数组用在你的response()中。

因此,在您的控制器中,您可以执行return response(StudentTransformer::transform(Student::all())) 之类的操作,而不是执行return response(Student::all()); 之类的操作。

这里的好处是您只有一个文件夹(您的Transformers)来检查响应数据格式。缺点是当你的数据库发生变化时,你还需要更新你的转换器。

【讨论】:

以上是关于Laravel 5 leftJoin on belongsTo 关系的主要内容,如果未能解决你的问题,请参考以下文章

mysql 加入 ON 和 AND 到 laravel eloquent

Laravel 5.2使用sum()更快地优化左连接

如何使用 Laravel 5.1 执行原始查询?

如何在laravel 5.4中进行左连接

LARAVEL 5.3,获取用户名和角色名(使用 Laravel 模型关系)

Laravel 5.8 在数据透视表上保存一对多关系