Eloquent:如何在不删除任何内容的情况下同步一对多关系(FK 可以为空)?

Posted

技术标签:

【中文标题】Eloquent:如何在不删除任何内容的情况下同步一对多关系(FK 可以为空)?【英文标题】:Eloquent: How to sync in one to many relations without deleting anything (FK is nullable)? 【发布时间】:2019-03-22 16:52:42 【问题描述】:

分行可能有(*) 或只有一个假期计划。假期计划可以“链接”(附加)到零个或多个分支。

(*) 这很重要:它是Foreign Key,可能是null

型号

这是我的Branch 模特:

class Branch extends Model

    protected $table = 'branch';
    protected $fillable = ['name', 'holiday_plan_id'];
    public $timestamps = false;

    public function holidayPlan()
    
        return $this->hasOne('App\HolidayPlan', 'id', 'holiday_plan_id');
    


这是我的HolidayPlan 模特:

class HolidayPlan extends Model

    protected $table = 'holiday_plan';
    protected $fillable = ['name'];
    public $timestamps = false;

    public function branches()
    
        return $this->hasMany('App\Branch', 'holiday_plan_id', 'id');
    


查看

现在我想将假期计划链接/取消链接到不同的分支机构

$branches = Branch::all();
$plan = HolidayPlan::find(1);

@foreach($branches as $branch)
<label>
    <input type="checkbox" name="branch[]"
        value=" $branch->id " ($branch->holiday_plan_id == $plan->id) ? ' checked' : '' >
     $branch->name 
</label>
@endforeach

控制器

public function linkBranches($planId, Request $request) // post

    $plan = HolidayPlan::where('id', $planId)->first();
    $branches = Branch::findMany($request->input('branch'));
    //
    $this->solution1($plan, $branches); // see next
    //
    return redirect()->back();


可能的解决方案(无效)

private function solution1(HolidayPlan $plan, $branches)

    $plan->branches()->sync($branches); // Not working because this function is for Many-to-Many relations


private function solution2(HolidayPlan $plan, $branches)

    $plan->branches()->delete(); // This will delete my branches, which is not what I want to do, of course
    $plan->branches()->saveMany($branches);


private function solution3(HolidayPlan $plan, $branches)

    foreach($plan->branches as $branch) 
        $branch->holiday_plan_id = null;
        $branch->save();
    
    $plan->branches()->saveMany($branches); // Not working; I don't know why: strange behavior. Maybe because of locks; I'm not sure. One time it detaches all branches, and only next time it attaches them again.


终于

实际上,原始 SQL 应该是:

UPDATE branch SET holiday_plan_id = NULL WHERE holiday_plan_id = 1;
UPDATE branch SET holiday_plan_id = 1 WHERE branch.id IN (2, 5, 7)/* for example */;

但是如何使用 Eloquent 函数和关系(没有原始 sql)来做到这一点?


编辑

我已经编辑了我的Branch 模型关系,但是solution3 仍然不起作用(当我尝试添加一个已经存在的holiday_plan_id 时,它没有添加它= 它变为空):

public function holidayPlan()

    return $this->belongsTo('App\HolidayPlan', 'holiday_plan_id');

【问题讨论】:

不删除任何东西,这取决于你的表。大多数数据库上的外键(holiday_plan_fk)可以设置为:(1)级联删除, (2) 什么都不做,(3) 设置为空。 on (1) 当您删除外键引用的一行时,它也会删除其他行。 (2) 如果特定行的 id 仍然在另一行上引用,则会限制您在 mysql 上执行任何操作。在 (3) 上,它会简单地将外键设置为 null .. 所以.. 告诉我们您的数据库引擎是什么以及生成数据库的迁移或至少 sql 脚本。干杯! 查看这些:(1) cascade delete,(2) do nothing,和 (3) set null do。希望我不会误解你的问题.. 这是另一个问题。谢谢你的信息。我正在删除任何内容。 啊,试过$plan-&gt;branches()-&gt;dissociate() 在您的模型中,您要指定列名。这些是完全多余的。您还应该在 Branch to HolidayPlan 模型中使用 belongsTo。 【参考方案1】:

临时解决方案:

public function solution4(HolidayPlan $plan, $inputBranches)

    $oldLinks = $plan->branches;
    $plan->branches()->saveMany($inputBranches);
    foreach ($oldLinks as $oldLink) 
        if (! $inputBranches->contains($oldLink)) 
            $oldLink->holiday_plan_id = null;
            $oldLink->save();
        
    

【讨论】:

以上是关于Eloquent:如何在不删除任何内容的情况下同步一对多关系(FK 可以为空)?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不删除任何文件的情况下从跟踪中分离文件夹?

如何在不发送任何内容的情况下检查频道是不是已满[重复]

如何在不隐藏内容的情况下删除双倍 y 滚动?

如何在不删除跨度的情况下更改 html 段落内容?

如何在不删除内容的情况下取消暂存大量文件

psql - 如何在不删除表的情况下刷新数据库内容