はじめに
リレーションについて整理します。
しっかり使えば複雑なSQLを使用する必要はないはずです。
今回の例はすべて1対多または多対1です。
例
以下の例を考えます、Eloquent ORMを使用しています。
$reports = Report::with([
'location',
'organization.tempSiteOrganizations',
'reportDetails.equipment.equipmentType'
])->get();
同等のSQLは以下のようになります。
リレーションを活用すれば簡潔に書けることがわかります!
SELECT
reports.id AS report_id,
locations.name AS location_name,
organizations.name AS organization_name,
temp_sites.name AS temp_site_name,
report_details.start_time,
report_details.end_time,
equipment.name AS equipment_name,
equipment_types.name AS equipment_type_name
FROM
reports
JOIN
locations ON reports.location_id = locations.id
JOIN
organizations ON reports.organization_id = organizations.id
JOIN
temp_site_organizations ON organizations.id = temp_site_organizations.organization_id
JOIN
temp_sites ON temp_site_organizations.temp_site_id = temp_sites.id
JOIN
report_details ON reports.id = report_details.report_id
JOIN
equipment ON report_details.equipment_id = equipment.id
JOIN
equipment_types ON equipment.equipment_type_id = equipment_types.id;
ルール
Eloquent ORMを使用する際、データベーステーブルとモデルの間の関係を適切に設定するためには、いくつかのルールやベストプラクティスに従うことが重要です。これにより、複雑なSQLクエリを書く必要がなくなり、簡潔で可読性の高いコードを書くことができます。以下に、Laravel/Eloquentを使用する際のテーブル作成のルールを記載します。
1. テーブル名とモデル名の規則
テーブル名
-
複数形を使用します。例えば、
User
モデルに対してはusers
テーブルを使用します。 - スネークケース(アンダースコアで単語を区切る)を使用します。例えば、
UserProfile
モデルに対してはuser_profiles
テーブルを使用します。
モデル名
-
単数形を使用します。例えば、
users
テーブルに対してはUser
モデルを使用します。 - キャメルケース(各単語の最初の文字を大文字にする)を使用します。例えば、
user_profiles
テーブルに対してはUserProfile
モデルを使用します。
2. 主キーとタイムスタンプ
- テーブルには通常、自動インクリメントの主キー
id
を使用します。 - テーブルには
created_at
とupdated_at
のタイムスタンプカラムを含めます。これらはEloquentが自動的に管理します。
3. 外部キーの命名規則
- 外部キーは関連するモデルの単数形の名前に
_id
を付けた形式を使用します。例えば、posts
テーブルにuser_id
カラムを含めてusers
テーブルとのリレーションを表現します。
4. リレーションシップの設定
- モデル内でリレーションシップメソッドを定義します。例えば、
User
モデルが複数のPost
を持つ場合、User
モデルにposts
メソッドを定義します。
5. その他のリレーションシップ
-
1対1(One to One):例えば、
User
がProfile
を持つ場合。 -
多対多(Many to Many):例えば、
User
が複数のRole
を持ち、Role
が複数のUser
を持つ場合。 -
ポリモーフィックリレーション:例えば、
Post
やComment
がTag
を持つ場合。
これらのルールに従うことで、Eloquent ORMを最大限に活用し、複雑なSQLクエリを書くことなく、シンプルで可読性の高いコードを書くことができます。
テーブル構成
今回使用するテーブルを作成します。
ER図
テーブル関係をER図で描画します。
以下の図では、各テーブルをエンティティとして、関連性を矢印で示します。
このER図は、各テーブルのカラム(フィールド)とそれらのリレーションシップ(関連性)を示しています。 PK
は主キー、FK
は外部キーを示しています。
テーブル構造
以下に、Report
、Location
、Organization
、TempSiteOrganizations
、ReportDetails
、Equipment
、およびEquipmentType
のテーブル構造の例を提示します。
reports
Column | Type | Description |
---|---|---|
id | BIGINT | Primary key |
location_id | BIGINT | Foreign key to locations |
organization_id | BIGINT | Foreign key to organizations |
created_at | TIMESTAMP | Creation timestamp |
updated_at | TIMESTAMP | Update timestamp |
locations
Column | Type | Description |
---|---|---|
id | BIGINT | Primary key |
name | VARCHAR | Name of the location |
created_at | TIMESTAMP | Creation timestamp |
updated_at | TIMESTAMP | Update timestamp |
organizations
Column | Type | Description |
---|---|---|
id | BIGINT | Primary key |
name | VARCHAR | Name of the organization |
created_at | TIMESTAMP | Creation timestamp |
updated_at | TIMESTAMP | Update timestamp |
temp_site_organizations
Column | Type | Description |
---|---|---|
id | BIGINT | Primary key |
organization_id | BIGINT | Foreign key to organizations |
temp_site_id | BIGINT | Foreign key to temp sites |
created_at | TIMESTAMP | Creation timestamp |
updated_at | TIMESTAMP | Update timestamp |
report_details
Column | Type | Description |
---|---|---|
id | BIGINT | Primary key |
report_id | BIGINT | Foreign key to reports |
equipment_id | BIGINT | Foreign key to equipment |
start_time | TIME | Work start time |
end_time | TIME | Work end time |
created_at | TIMESTAMP | Creation timestamp |
updated_at | TIMESTAMP | Update timestamp |
equipment
Column | Type | Description |
---|---|---|
id | BIGINT | Primary key |
name | VARCHAR | Name of the equipment |
equipment_type_id | BIGINT | Foreign key to equipment types |
created_at | TIMESTAMP | Creation timestamp |
updated_at | TIMESTAMP | Update timestamp |
equipment_types
Column | Type | Description |
---|---|---|
id | BIGINT | Primary key |
name | VARCHAR | Type of the equipment |
created_at | TIMESTAMP | Creation timestamp |
updated_at | TIMESTAMP | Update timestamp |
マイグレーションファイル作成
テーブル作成にあたりマイグレーションを使用します。
以下に、各コマンドとそれによって生成されるマイグレーションファイルの内容をセットで記載します。
1. reports テーブル
コマンド:
./vendor/bin/sail artisan make:migration create_reports_table --create=reports
生成されるファイル (database/migrations/xxxx_xx_xx_xxxxxx_create_reports_table.php
):
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateReportsTable extends Migration
{
public function up()
{
Schema::create('reports', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('location_id');
$table->unsignedBigInteger('organization_id');
$table->timestamps();
$table->foreign('location_id')->references('id')->on('locations');
$table->foreign('organization_id')->references('id')->on('organizations');
});
}
public function down()
{
Schema::dropIfExists('reports');
}
}
2. locations テーブル
コマンド:
./vendor/bin/sail artisan make:migration create_locations_table --create=locations
生成されるファイル (database/migrations/xxxx_xx_xx_xxxxxx_create_locations_table.php
):
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateLocationsTable extends Migration
{
public function up()
{
Schema::create('locations', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('locations');
}
}
3. organizations テーブル
コマンド:
./vendor/bin/sail artisan make:migration create_organizations_table --create=organizations
生成されるファイル (database/migrations/xxxx_xx_xx_xxxxxx_create_organizations_table.php
):
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateOrganizationsTable extends Migration
{
public function up()
{
Schema::create('organizations', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('organizations');
}
}
4. temp_site_organizations テーブル
コマンド:
./vendor/bin/sail artisan make:migration create_temp_site_organizations_table --create=temp_site_organizations
生成されるファイル (database/migrations/xxxx_xx_xx_xxxxxx_create_temp_site_organizations_table.php
):
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTempSiteOrganizationsTable extends Migration
{
public function up()
{
Schema::create('temp_site_organizations', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('organization_id');
$table->unsignedBigInteger('temp_site_id');
$table->timestamps();
$table->foreign('organization_id')->references('id')->on('organizations');
// Assuming temp_sites table exists
$table->foreign('temp_site_id')->references('id')->on('temp_sites');
});
}
public function down()
{
Schema::dropIfExists('temp_site_organizations');
}
}
5. report_details テーブル
コマンド:
./vendor/bin/sail artisan make:migration create_report_details_table --create=report_details
生成されるファイル (database/migrations/xxxx_xx_xx_xxxxxx_create_report_details_table.php
):
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateReportDetailsTable extends Migration
{
public function up()
{
Schema::create('report_details', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('report_id');
$table->unsignedBigInteger('equipment_id');
$table->time('start_time');
$table->time('end_time');
$table->timestamps();
$table->foreign('report_id')->references('id')->on('reports');
$table->foreign('equipment_id')->references('id')->on('equipment');
});
}
public function down()
{
Schema::dropIfExists('report_details');
}
}
6. equipment テーブル
コマンド:
./vendor/bin/sail artisan make:migration create_equipment_table --create=equipment
生成されるファイル (database/migrations/xxxx_xx_xx_xxxxxx_create_equipment_table.php
):
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateEquipmentTable extends Migration
{
public function up()
{
Schema::create('equipment', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->unsignedBigInteger('equipment_type_id');
$table->timestamps();
$table->foreign('equipment_type_id')->references('id')->on('equipment_types');
});
}
public function down()
{
Schema::dropIfExists('equipment');
}
}
7. equipment_types テーブル
コマンド:
./vendor/bin/sail artisan make:migration create_equipment_types_table --create=equipment_types
生成されるファイル (database/migrations/xxxx_xx_xx_xxxxxx_create_equipment_types_table.php
):
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateEquipmentTypesTable extends Migration
{
public function up()
{
Schema::create('equipment_types', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('equipment_types');
}
}
8.temp_sites
テーブル
生成されるファイル (database/migrations/xxxx_xx_xx_xxxxxx_create_temp_sites_table.php
):
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTempSitesTable extends Migration
{
public function up()
{
Schema::create('temp_sites', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('temp_sites');
}
}
依存関係
上記はphp artisan mygrateではエラーになります。
マイグレーションの実行順序を確認し、依存関係を正しく反映させるために、以下の順序でマイグレーションを実行します。
マイグレーション実行順序
-
locations
テーブル -
organizations
テーブル -
temp_sites
テーブル -
equipment_types
テーブル -
equipment
テーブル -
reports
テーブル -
temp_site_organizations
テーブル -
report_details
テーブル
# 順番にマイグレーションを実行
./vendor/bin/sail artisan migrate --path=/database/migrations/2024_06_20_071800_create_locations_table.php
./vendor/bin/sail artisan migrate --path=/database/migrations/2024_06_20_071802_create_organizations_table.php
./vendor/bin/sail artisan migrate --path=/database/migrations/2024_06_20_071804_create_temp_sites_table.php
./vendor/bin/sail artisan migrate --path=/database/migrations/2024_06_20_071806_create_equipment_types_table.php
./vendor/bin/sail artisan migrate --path=/database/migrations/2024_06_20_072055_create_equipment_table.php
./vendor/bin/sail artisan migrate --path=/database/migrations/2024_06_20_071808_create_reports_table.php
./vendor/bin/sail artisan migrate --path=/database/migrations/2024_06_20_071810_create_temp_site_organizations_table.php
./vendor/bin/sail artisan migrate --path=/database/migrations/2024_06_20_072000_create_report_details_table.php
データセット
データをセットします、まずテストデータをデータベースに挿入する必要があります。以下の手順でデータをセットしていきます。
1. モデルとリレーションの設定
まず、各モデルのリレーションを設定します。
Location モデル
./vendor/bin/sail artisan make:model Location
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Location extends Model
{
use HasFactory;
protected $fillable = ['name'];
public function reports()
{
return $this->hasMany(Report::class);
}
}
Organization モデル
./vendor/bin/sail artisan make:model Organization
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Organization extends Model
{
use HasFactory;
protected $fillable = ['name'];
public function tempSiteOrganizations()
{
return $this->hasMany(TempSiteOrganization::class);
}
public function reports()
{
return $this->hasMany(Report::class);
}
}
TempSite モデル
./vendor/bin/sail artisan make:model TempSite
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class TempSite extends Model
{
use HasFactory;
protected $fillable = ['name'];
public function tempSiteOrganizations()
{
return $this->hasMany(TempSiteOrganization::class);
}
}
TempSiteOrganization モデル
./vendor/bin/sail artisan make:model TempSiteOrganization
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class TempSiteOrganization extends Model
{
use HasFactory;
protected $fillable = ['organization_id', 'temp_site_id'];
public function organization()
{
return $this->belongsTo(Organization::class);
}
public function tempSite()
{
return $this->belongsTo(TempSite::class);
}
}
Report モデル
./vendor/bin/sail artisan make:model Report
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Report extends Model
{
use HasFactory;
protected $fillable = ['location_id', 'organization_id'];
public function location()
{
return $this->belongsTo(Location::class);
}
public function organization()
{
return $this->belongsTo(Organization::class);
}
public function reportDetails()
{
return $this->hasMany(ReportDetail::class);
}
}
ReportDetail モデル
./vendor/bin/sail artisan make:model ReportDetail
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ReportDetail extends Model
{
use HasFactory;
protected $fillable = ['report_id', 'equipment_id', 'start_time', 'end_time'];
public function report()
{
return $this->belongsTo(Report::class);
}
public function equipment()
{
return $this->belongsTo(Equipment::class);
}
}
Equipment モデル
./vendor/bin/sail artisan make:model Equipment
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Equipment extends Model
{
use HasFactory;
protected $fillable = ['name', 'equipment_type_id'];
public function equipmentType()
{
return $this->belongsTo(EquipmentType::class);
}
public function reportDetails()
{
return $this->hasMany(ReportDetail::class);
}
}
EquipmentType モデル
./vendor/bin/sail artisan make:model EquipmentType
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class EquipmentType extends Model
{
use HasFactory;
protected $fillable = ['name'];
public function equipment()
{
return $this->hasMany(Equipment::class);
}
}
2. シーダーでデータをセットする
データベースシーダーを作成して、テストデータを挿入します。
DatabaseSeeder
database/seeders/DatabaseSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\Location;
use App\Models\Organization;
use App\Models\TempSite;
use App\Models\TempSiteOrganization;
use App\Models\Report;
use App\Models\ReportDetail;
use App\Models\Equipment;
use App\Models\EquipmentType;
class DatabaseSeeder extends Seeder
{
public function run()
{
// 5つのロケーションを生成
for ($i = 1; $i <= 5; $i++) {
$location = Location::create(['name' => 'Location ' . $i]);
// 5つの組織を生成
for ($j = 1; $j <= 5; $j++) {
$organization = Organization::create(['name' => 'Organization ' . $j]);
// 1つの一時サイトを生成
$tempSite = TempSite::create(['name' => 'Temp Site ' . $i . '-' . $j]);
// 一時サイトと組織の関係を生成
$tempSiteOrganization = TempSiteOrganization::create([
'organization_id' => $organization->id,
'temp_site_id' => $tempSite->id,
]);
// 1つのレポートを生成
$report = Report::create([
'location_id' => $location->id,
'organization_id' => $organization->id,
]);
// 1つの機器タイプを生成
$equipmentType = EquipmentType::create(['name' => 'Type ' . $i . '-' . $j]);
// 1つの機器を生成
$equipment = Equipment::create([
'name' => 'Equipment ' . $i . '-' . $j,
'equipment_type_id' => $equipmentType->id,
]);
// レポート詳細を生成
ReportDetail::create([
'report_id' => $report->id,
'equipment_id' => $equipment->id,
'start_time' => '08:00:00',
'end_time' => '17:00:00',
]);
}
}
}
}
このシーダーを実行することで、データベースに必要なテストデータが挿入されます。
3. シーダーの実行
以下のコマンドを実行してシーダーを実行し、データを挿入します。
./vendor/bin/sail artisan db:seed
4. データの取得
これで、指定したクエリを実行してデータを取得できるはずです。
$reports = Report::with([
'location',
'organization.tempSiteOrganizations',
'reportDetails',
'reportDetails.equipment.equipmentType'
])->get();
この手順でデータをセットし、取得することができます。他にご質問があればお知らせください。
データ確認
シーダーが実行できたことを確認した後、データを表示させてみます。
1. コントローラーの作成
データを取得して表示するためのコントローラーを作成します。
./vendor/bin/sail artisan make:controller ReportController
2. コントローラーの編集
作成したコントローラーにデータを取得してビューに渡す処理を追加します。
app/Http/Controllers/ReportController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Report;
class ReportController extends Controller
{
public function index()
{
$reports = Report::with([
'location',
'organization.tempSiteOrganizations',
'reportDetails.equipment.equipmentType'
])->get();
return view('reports.index', compact('reports'));
}
}
3. ビューの作成
ビューを作成して、データを表示します。
ビューのファイル作成
resources/views/reports/index.blade.php
<!DOCTYPE html>
<html>
<head>
<title>Reports</title>
</head>
<body>
<h1>Reports</h1>
@foreach ($reports as $report)
<h2>Report ID: {{ $report->id }}</h2>
<p>Location: {{ $report->location->name }}</p>
<p>Organization: {{ $report->organization->name }}</p>
<h3>Temp Site Organizations:</h3>
<ul>
@foreach ($report->organization->tempSiteOrganizations as $tempSiteOrganization)
<li>{{ $tempSiteOrganization->tempSite->name }}</li>
@endforeach
</ul>
<h3>Report Details:</h3>
<ul>
@foreach ($report->reportDetails as $detail)
<li>
Start Time: {{ $detail->start_time }},
End Time: {{ $detail->end_time }},
Equipment: {{ $detail->equipment->name }},
Equipment Type: {{ $detail->equipment->equipmentType->name }}
</li>
@endforeach
</ul>
@endforeach
</body>
</html>
4. ルートの設定
ルートを設定してコントローラーのメソッドを呼び出すようにします。
routes/web.php
use App\Http\Controllers\ReportController;
Route::get('/reports', [ReportController::class, 'index']);
5. アプリケーションの起動と確認
アプリケーションを起動してデータが表示されることを確認します。
./vendor/bin/sail up
ブラウザで http://localhost/reports
にアクセスして、データが表示されることを確認します。
これで、シーダーで挿入したデータをビューで表示させることができます。
データ取得説明
$reports = Report::with([...])->get();
に関する詳細な説明と、各依存関係の説明を記載します。
コードの詳細と依存関係
$reports = Report::with([
'location',
'organization.tempSiteOrganizations',
'reportDetails.equipment.equipmentType'
])->get();
クエリ例
array:7 [▼ // app/Http/Controllers/ReportController.php:25
0 => array:3 [▼
"query" => "select * from `reports`"
"bindings" => []
"time" => 1.25
]
1 => array:3 [▼
"query" => "select * from `locations` where `locations`.`id` in (1, 2, 3, 4, 5, 6)"
"bindings" => []
"time" => 0.77
]
2 => array:3 [▼
"query" => "select * from `organizations` where `organizations`.`id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)"
"bindings" => []
"time" => 0.69
]
3 => array:3 [▼
"query" => "
select * from `temp_site_organizations` where `temp_site_organizations`.`organization_id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)
◀
"
"bindings" => []
"time" => 0.8
]
4 => array:3 [▼
"query" => "
select * from `report_details` where `report_details`.`report_id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)
◀
"
"bindings" => []
"time" => 0.57
]
5 => array:3 [▼
"query" => "select * from `equipment` where `equipment`.`id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)"
"bindings" => []
"time" => 0.5
]
6 => array:3 [▼
"query" => "select * from `equipment_types` where `equipment_types`.`id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)"
"bindings" => []
"time" => 0.99
]
実行されるクエリの詳細とその意味
1. レポートの取得
select * from `reports`
- これは
reports
テーブルからすべてのレポートを取得します。
2. ロケーションの取得
select * from `locations` where `locations`.`id` in (1, 2, 3, 4, 5, 6)
- 取得されたレポートの
location_id
に基づいて、対応するロケーションをlocations
テーブルから取得します。
3. 組織の取得
select * from `organizations` where `organizations`.`id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)
- 取得されたレポートの
organization_id
に基づいて、対応する組織をorganizations
テーブルから取得します。
4. 一時サイトと組織の関係の取得
select * from `temp_site_organizations` where `temp_site_organizations`.`organization_id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)
- 取得された組織の
id
に基づいて、一時サイトと組織の関係をtemp_site_organizations
テーブルから取得します。
5. レポート詳細の取得
select * from `report_details` where `report_details`.`report_id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)
- 取得されたレポートの
id
に基づいて、対応するレポート詳細をreport_details
テーブルから取得します。
6. 機器の取得
select * from `equipment` where `equipment`.`id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)
- 取得されたレポート詳細の
equipment_id
に基づいて、対応する機器をequipment
テーブルから取得します。
7. 機器タイプの取得
select * from `equipment_types` where `equipment_types`.`id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)
- 取得された機器の
equipment_type_id
に基づいて、対応する機器タイプをequipment_types
テーブルから取得します。
データの取得
このクエリを実行すると、Report
のデータとその関連情報が一度に取得されます。例えば、以下のようなデータ構造が取得されます。
foreach ($reports as $report) {
echo "Report ID: " . $report->id . "\n";
echo "Location: " . $report->location->name . "\n";
echo "Organization: " . $report->organization->name . "\n";
foreach ($report->reportDetails as $detail) {
echo "Detail ID: " . $detail->id . "\n";
echo "Equipment: " . $detail->equipment->name . "\n";
echo "Equipment Type: " . $detail->equipment->equipmentType->name . "\n";
}
}
-
Report
から関連するLocation
,Organization
,ReportDetails
の情報を一緒に取得しています。 -
ReportDetail
からEquipment
とそのEquipmentType
の情報も取得しています。
Report
モデルの関連付け
このクエリは Report
モデルからデータを取得し、以下の関連モデルも一緒にロードしています。
-
location
:-
Report
とLocation
のリレーションです。Report
がLocation
に属することを示します。 -
例:
Report
がLocation
のid
をlocation_id
として持つ。
-
-
organization.tempSiteOrganizations
:-
Report
とOrganization
のリレーションで、さらにOrganization
が複数のTempSiteOrganization
と関連していることを示します。 -
例:
Organization
モデルにTempSiteOrganization
モデルとのリレーションが定義されている。
-
-
reportDetails.equipment.equipmentType
:-
Report
の詳細情報 (ReportDetails
) を取得し、その詳細がEquipment
とEquipmentType
に関連していることを示します。 -
例:
ReportDetails
がEquipment
のequipment_id
を持ち、さらにそのEquipment
がEquipmentType
に属する。
-
比較
提供されたEloquentクエリは、SQLクエリと同等の結果を返します。Eloquent ORMを使用することで、リレーションシップを利用したデータの取得が簡潔に行えますが、内部的には以下のようなSQLクエリを実行しています。
Eloquentクエリ
$reports = Report::with([
'location',
'organization.tempSiteOrganizations',
'reportDetails.equipment.equipmentType'
])->get();
同等のSQLクエリ
SELECT
reports.id AS report_id,
locations.name AS location_name,
organizations.name AS organization_name,
temp_sites.name AS temp_site_name,
report_details.start_time,
report_details.end_time,
equipment.name AS equipment_name,
equipment_types.name AS equipment_type_name
FROM
reports
JOIN
locations ON reports.location_id = locations.id
JOIN
organizations ON reports.organization_id = organizations.id
JOIN
temp_site_organizations ON organizations.id = temp_site_organizations.organization_id
JOIN
temp_sites ON temp_site_organizations.temp_site_id = temp_sites.id
JOIN
report_details ON reports.id = report_details.report_id
JOIN
equipment ON report_details.equipment_id = equipment.id
JOIN
equipment_types ON equipment.equipment_type_id = equipment_types.id;
2つの結果は同じデータを返します。ただし、取得方法が異なります。
同じデータを取得するが、方法が異なる
-
Eloquentクエリ:
- 内部的に複数のSQLクエリを発行して関連データを取得します。
- 各モデル間のリレーションシップに基づいてデータをロードします。
- 直感的でメンテナンスが容易なコードを書くことができます。
-
SQLクエリ:
- 単一のクエリで複数のテーブルをJOINしてデータを取得します。
- リレーションシップを手動で定義する必要があります。
- SQLの知識が必要ですが、特定のシナリオではパフォーマンスが向上することがあります。
結果の一致
両方のアプローチは同じデータを取得しますが、Eloquentはリレーションシップを抽象化して扱いやすくし、SQLは直接的で効率的なデータ取得を行います。
参考記事