Laravel - Eloquent - 获得没有外键的关系

Posted

技术标签:

【中文标题】Laravel - Eloquent - 获得没有外键的关系【英文标题】:Laravel - Eloquent - Get a ralationship without foreign key 【发布时间】:2021-10-29 07:26:41 【问题描述】:

我正在做一个 Laravel 项目,我有模型“预订”和“周”。

型号“Week”有开始日期和价格,型号“Reservation”有开始日期和结束日期。

我希望能够像这样做一个有说服力的选择:Reservation::with('weeks')->get(),但是如果我在 eloquent 以下做一些事情,就不会将其识别为关系,并且我不能在 Reservation 模型中使用“HasMany”,因为我不要将表格与 id 相关联,而仅与日期相关联。

我怎样才能获得一段关系的周数?

class Reservation extends Model

    public function weeks()
            
                return Week::whereDate('starting_date', '>=', $this->starting_date)
                    ->whereDate('starting_date', '<', $this->ending_date)
                    ->orderBy('starting_date')
                    ->get();
            

已编辑:感谢@Tim Lewis

【问题讨论】:

Reservation::all()-&gt;with('weeks') 不行; ::all() 转换为没有 with() 方法的 Collection。请改用Reservation::with('weeks')-&gt;get()。但是,如果你不能定义关系,那也行不通。您不能急于加载 weeks (with('weeks')),因为它不会返回关系。 【参考方案1】:

感谢这个存储库,我终于成功了:https://github.com/johnnyfreeman/laravel-custom-relation

存储库已存档,无法为 Laravel 8 安装,所以我只是复制了此文件夹中的文件:

app\Relations\Custom.php app\Traits\HasCustomRelations.php

这允许我使用带有前缘约束的Reservation::with('weeks')-&gt;get();

use App\Models\Week;
use App\Traits\HasCustomRelations;

class Reservation extends Model

    use HasCustomRelations;

    public function weeks()
    
        return $this->custom(
            Week::class,

            // add constraints
            function ($relation) 
                if($this->starting_date && $this->ending_date) 
                    $relation->getQuery()
                        ->where('weeks.starting_date', '>=', $this->starting_date)
                        ->where('weeks.starting_date', '<',  $this->ending_date);
                
                else 
                    $relation->getQuery();
                
            ,

            // add eager constraints
            function ($relation, $models) 
                $starting_date = $models[0]->starting_date;
                $ending_date = $models[count($models)-1]->ending_date;
                $relation->getQuery()
                    ->where('weeks.starting_date', '>=', $starting_date)
                    ->where('weeks.starting_date', '<', $ending_date);
            ,

            // add eager matcher
            function ($models, $results, $foreignTable, $relation) 
                foreach ($models as $model) 
                    $model->setRelation($foreignTable, $results
                        ->where('starting_date', '>=', $model->starting_date)
                        ->where('starting_date', '<',  $model->ending_date));
                
                return $models;
            
        );
    


【讨论】:

【参考方案2】:

你快到了。只需使用访问器来获取周数:

public function getWeeksAttribute()

    return Week::whereDate('starting_date', '>=', $this->starting_date)
        ->whereDate('starting_date', '<', $this->ending_date)
        ->orderBy('starting_date')
        ->get();

您将能够像获取任何其他属性一样获取周数。如果您需要将模型序列化为 Json,请记住将 weeks 添加到模型中的 $appends array 中。

【讨论】:

谢谢,如果我这样做,这项工作:Reservation::first()->weeks 但如果我这样做:Reservation::with('weeks')->first()我收到此错误:调用模型 [App\Models\Reservation] 上的未定义关系 [weeks]。 您不要使用“with”,因为这是一个访问者,而不是关系。由于您的两个表中的任何一个都没有外键,因此不可能建立真正的关系。我相信这是下一个最佳解决方案。 访问器也可以在模型中不指定 $appends 的情况下工作,但使用 Reservation::first()->append('weeks'),但我想要做的是 ->with('weeks' ) 进行查询优化。如果我选择更多保留,则使用访问器,append 方法会为每个模型执行查询。对我来说最好的解决方案可能是没有foreign_key的“HasMany”关系,但我不知道该怎么做

以上是关于Laravel - Eloquent - 获得没有外键的关系的主要内容,如果未能解决你的问题,请参考以下文章

Laravel,获得类似 Eloquent 使用查询生成器的结果

Laravel Eloquent 如何根据计数获得关系总和

Laravel Eloquent - 如何获得嵌套关系

laravel Eloquent ORM - 如何获得编译查询?

Laravel Eloquent 关系方法语法

Laravel Vue - 在 json 响应中获得 Eloquent