Laravel Eloquent 多表内连接查询

10

我目前正在执行一个原始的SQL查询,但这会导致关系和模型引导方法出现问题。

是否可以使用Laravel Eloquent模型通过关系来执行以下SQL查询?请注意,所有的数据库表都有定义的外键,并且关系要么是HasOne关系,要么是HasMany关系。

    $timeBreakDown = DB::select(
        "SELECT
                Entries.`task_id`,
                Entries.`opportunity_id`,
                SUM(Entries.`total_duration`) as 'duration',
                Class.`class` as 'class',
                Subclass.`sub_class` as 'subclass'
            from entries Entries
                INNER JOIN `tasks` Task
                    ON task_id = Task.id
                INNER JOIN `task_class` Class
                    ON Task.`class_id` = Class.`id`
                INNER JOIN `task_subclasses` Subclass
                    ON Task.`subclass_id` = Subclass.`id`
                WHERE Entries.`opportunity_id` = '".$opportunity->id."'
                GROUP BY Entries.`task_id`"
    );

模型是什么?

Entries
Tasks
Class
Subclass

如何构建模型关系以处理上述SQL查询?

enter image description here


我可以问一下,为什么您更喜欢使用连接而不是Eloquent关系吗? - Skywarth
我不知道如何通过关系处理来执行该查询以得到一个诚实的答案。@Skywarth - levi
Eloquent和join不搭配。你是指查询构建器吗? - miken32
1
@kray 你可以尝试使用这个附加包Eloquent Power Joins来使用连接作为关系。 - Haridarshan
8个回答

3

你可以用以下方式编写查询语句:
请根据你的数据库检查表名。

DB:: table('table name')->join('tasks','task_id','=','tasks.id')
->join('task_class', 'tasks.subclass_id','=','task_class.id')
->join('task_subclasses','tasks.subclass_id','=', 'task_subclasses.id')
->selectRaw('entries.task_id,
            task_subclasses.opportunity_id,
            SUM(entries.total_duration) as duration,
            task_class.class as class,
            task_subclasses.sub_class as subclass') 
->where(['entries.opportunity_id'=>$opportunity->id])
->groupBy('enteries.task_id')->get();

1

Models\Entries.php

<?php

namespace App\Models;


use Illuminate\Database\Eloquent\Model;

class Entries extends Model
{
    public function Tasks(){
        return $this->hasOne(Tasks::class);
    }
    public function Class(){
        return $this->hasMany(Classes::class);
    }
    public function SubClasses(){
        return $this->hasOne(SubClasses::class);
    }
}

Models\Tasks.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Tasks extends Model
{
    public function Entries(){
        return $this->belongsTo(Entries::class, "id", "task_id");
    }
}

Models\Classes.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Classes extends Model
{
    public function Entries(){
        return $this->belongsTo(Entries::class, "class_id", "id");
    }
}

Models\Subclasses.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class SubClasses extends Model
{
    public function Entries(){
        
        return $this->belongsTo(Entries::class, "id", "subclass_id");
        
    }
}

查询:

Entries::with([
        "Tasks",
        "Classes",
        "SubClasses"
    ])
    ->where("opportunity_id", $opportunity->id)
    ->groupBy("task_id")
    ->get();

0

是的,您可以使用Eloquent来实现。我将与您分享一个示例。 很抱歉我无法阅读您混乱的查询语句,但我建议您这样做。

Entries::with(['Tasks','Class','Subclass'])->get();

从这里,您将获得此数组中的所有对象

就说吧

该类与另一个模型有关联,但不是Entries表,那么Eloquent就是这样的

Entries::with(['Tasks','Class.Subclass'])->get();

希望对你有所帮助


0

如果您能够发布您的模型,那对我们来说会更容易。但是根据您上面的原始查询,这是我得到的结果。

$timeBreakDown = Entries::where('opportunity_id',$opportunity->id)->load('Tasks','Class.SubClass')->get();

你应该了解 Laravel Eloquent 和关联关系。简单介绍一下 Waleed 使用的 load 和 with 之间的区别: load 用于关系数据的惰性加载,而 with 用于急切加载。
急切加载是在 Eloquent 查询数据时立即加载所有数据,而惰性加载则在需要时加载数据。

0

可能是这样的:

$timeBreakDown = Entries::select('entries.task_id, entries.opportunity_id', DB:raw('SUM(Entries.total_duration) as duration), task_class.class, task_subclasses.sub_class as subclass)
join('tasks', [['tasks.id', 'entries.task_id']])
join('task_class', [['task_class.id', 'entries.class_id']])
join('task_subclasses', [['task_subclasses.id', 'entries.subclass_id']])
->where('entries.opportunity_id', $opportunity->id)
->groupBy('entries.task_id')
->get();

0

尝试这个查询:

$timeBreakDown = Entries::join('tasks', 'tasks.id', '=', 'entries.task_id')
            ->join('class', 'class.id', '=', 'entries.class_id')
            ->join('subclass', 'subclass.id', '=', 'entries.subclass_id')
            ->select(
                'entries.task_id',
                'entries.opportunity_id',
                \DB::raw('SUM(entries.total_duration) as duration'),
                'class.class',
                'subclass.sub_class as subclass')
            ->where('entries.opportunity_id', $opportunity->id)
            ->groupBy('entries.task_id')
            ->get();

尝试使用dd($timeBreakDown->toSql());来匹配您的原始SQL查询。


那么,在进行连接时,您是按模型名称还是按数据库中的实际表名进行连接?如果是这样,难道没有更清晰的方法来处理该查询吗?与在许多查询中具有静态类型数据库名称相比,通过在模型内部执行更改表名以提高可维护性或进行未来更改的单个位置,不是更好吗? - levi
寻找更接近Mike Lucid回答的内容,但是他的回答关系有点混乱。我在我的原帖上重新发布了数据库关系的截图。 - levi

0
从官方文档中得知,您可以通过将tasks方法添加到“Entries”模型来使用基本的数据库关系类型定义关系。tasks方法应调用hasOne方法并返回其结果。
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Entries extends Model
{
    /**
     * Get the phone associated with the user.
     */
    public function task()
    {
        return $this->hasOne(Tasks::class);
    }
}

接下来,Tasks 模型将具有一个入口方法,我们可以使用 belongsTo 方法确定 hasOne 关系的反向关系:

<?php
    
  namespace App\Models;
   
  use Illuminate\Database\Eloquent\Model;
    
  class Tasks extends Model
  {
      /**
       * Get the user that owns the phone.
       */
      public function entry()
      {
          return $this->belongsTo(Entries::class);
      }
  }

请再看一下原帖。我添加了数据库布局的截图。我不认为你的答案是解决方案,它很接近,但我认为它不完整。 - levi

0

你只需要像这样设置关系:

我假设一个 Class 会有一个 subClass,并且一个 Class 还会有 Tasks,而这些 Tasks 又有 Entries

另外,你没有 User 模型吗?

Class 模型

class Class extends Model
{ 

  protected $with = ['entries', 'subclass', 'task'];

  public function entries()
  {
      return $this->hasManyThrough(\App\Models\Entries::class, \App\Models\Task::class);
  }

  public function subClass()
  {
      return $this->hasOne(\App\Models\subClass::class);
  }

  public function tasks()
  {
    return $this->hasMany(\App\Models\Task::class);
  }
}

入门级模型

class Entry extends Model
{ 

  protected $with = ['task'];

  public function task()
  {
    return $this->belongsTo(Task::class);
  }
}

子类模型

class SubClass extends Model
{ 

  protected $with = ['class'];

  public function class()
  {
    return $this->belongsTo(\App\Models\Class::class);
  }
}

任务模型

class Task extends Model
{ 

  protected $with = ['entries', 'class'];

  public function entries()
  {
      return $this->hasMany(\App\Models\Class::class);
  }

  public function class()
  {
    return $this->hasMany(\App\Models\Task::class);
  }
}

完成所有设置后,您应该可以在堆栈中的任何位置执行以下操作:

$entry = Entry::findOrFail('id');
$entry->task->class->subClass->name;

或者

$class = Class::findOrFail($class->id);
$subclass_name = $class->subclass->name;
$entries = $class->tasks->entries;

时间条目将通过任务ID拥有一个任务,任务是类和子类的组合查找表。因此,任务是类和子类的组合A-B|C B-B|A等等。时间条目将有一个用户,该用户具有其自己的关系,这在此查询中并不重要。我应该能够通过关系获取它。 - levi
我在帖子中添加了数据库图表的截屏。 - levi
你介意更新一下你的答案,将关系的正确顺序排列一下吗?@Mike Lucid - levi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接