【问题标题】:Laravel - Eloquent Relationship hasMany but also hasOne?Laravel - 雄辩的关系有很多但也有一个?
【发布时间】:2020-04-10 02:47:02
【问题描述】:

我已经在整个网络上苦苦挣扎了大约 2 个小时。

我有一个 USER 模型、一个 RUN 模型和一个 TIME 模型。

在现实世界中,用户正在比赛中,并将他们的时间与 USER_id 和 RUN_id 一起输入数据库。

对于每个 RUN_id,用户应该只能在 TIMES 表中拥有一行 - 如果这有意义的话!

这是我需要在控制器级别管理的事情吗?或者有没有我可以设置的关系来保证这种风格的重复条目不能进入数据库?

目前的数据库结构:


用户:

姓名


运行:

姓名


时间:

时间

user_id

run_id


模型:

用户:

public function times()
{
    return $this->hasMany(Time::class);
}

运行:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Run extends Model
{    
    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function times()
    {
        return $this->hasMany(Time::class);
    }
}

时间:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Time extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function run()
    {
        return $this->belongsTo(Run::class);
    }

}

【问题讨论】:

  • 用户模型上的组关系是什么?
  • USER 表必须有一个作为主键的 id 字段,还有 TIME 表。
  • @L.Fox - 这是一个单独的关系,我将从上面删除
  • USER与RUN有关系吗?
  • 您是否为时间表完成了迁移代码?如果是,则在 CreateTimesTable 函数中(在 database\migration\xxxxx_create_times_table.php 中)设置索引;此时可以根据run_id + user_id 设置唯一索引。看这里:stackoverflow.com/questions/20065697/…

标签: laravel eloquent laravel-6.2


【解决方案1】:

您可以在times 表上添加唯一键约束以强制 user_id 和 run_id 的唯一组合

$table->unique(['user_id, 'run_id']);

为了在应用程序级别验证唯一性,我们还可以在表单验证中添加一个约束。假设您在创建新时间的请求中同时传递了 user_id 和 run_id,您可以将以下内容添加到表单请求中

/**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'user_id' => Rule::unique('times')->where('run_id', $this->input('run_id'))
        ];
    }

    public function messages()
    {
        return [
            'user_id.unique' => 'A user may only have 1 time entry per Run'
        ];
    }

这将强制 user_id 在times 表中是唯一的,由该运行 ID 过滤。 messages 函数还返回更有用的错误消息,因为“user_id 必须是唯一的”在这种情况下没有帮助。

【讨论】:

  • 成功了,谢谢!我现在必须发布一个我认为的单独问题:)
  • 在向数据库添加行时如何检查这一点?或者这只是为了数据库完整性而不是 Laravel 来处理?
  • Laravel 的验证规则也可以使用复合键,让我试着写点东西,我会编辑我的答案
  • 好的,用您可以添加的表单验证规则更新答案。
  • 但是 - 现在,当我尝试提交运行时间时,我总是在每个用户身上收到消息“一个用户每次运行可能只有 1 个时间条目”..
【解决方案2】:

此答案应补充已接受的答案。您仍应将 user_id,run_id 对定义为唯一键。 但是,在您的情况下,用户和运行与 times 作为数据透视表具有 N-N 关系。你应该这样编码。

用户

public function runs()
{
    return $this->belongsToMany(Run::class, 'times')->withPivot('time');;
}

运行:

public function users()
{
    return $this->belongsToMany(User::class, 'times')->withPivot('time');
}

然后您可以将它们检索为:


$runs = User::find($userId)->runs; // Collection of all runs a user participated in
// $runs[X]->pivot->time has the time

您可以查看the documentation了解更多信息

【讨论】:

  • 我希望我能给出两个答案“最佳答案”。这个和另一个答案的结合帮助我实现了总体目标。这也是我检索没有运行的用户的方式: $runners = User::whereDoesntHave('runs', function($q) use($run) { $q->where('run_id', $run- >id); })->whereHas("roles", function($q){ // 只获取特定角色的用户 $q->where("name", "Student") ->orWhere("name", "PLT 学生"); })->get();
  • 刚刚意识到数据透视表可能不是最好的方法?一旦我想删除“时间”,它就会导致问题。数据透视表通常没有 ID,当我想删除“时间”时,我无法以正常方式访问它来删除它
  • 是的,在这种情况下,您需要从用户那里“分离”运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-01
  • 2020-06-30
  • 2019-06-18
  • 2017-10-17
  • 2012-10-08
  • 2018-10-27
  • 1970-01-01
相关资源
最近更新 更多