Laravel hasMany detach

2020-08-18 05:45发布

问题:

I am having an issue with Eloquent regarding removing child model: When this is executed in process2() I still have the deleted model which is not ok.

Model

    namespace App\Models;

    use Illuminate\Database\Eloquent\Model;

    class Model1 extends Model
    {
        public function seasons() {
            return $this->hasMany('App\Models\Seasons', 'series_id', 'id');
        }
    }

Service

class Process {
    public function process1($model1Instance) {

        for($model1Instance->seasons() as $season) {
            if(//whatever//) {
                $season->delete();
            }
        }
    }
    public function process2($model1Instance) {
        for($model1Instance->seasons() as $season) {
            //At this point I still have the deleted instance
        }
    }
}

Usage

$proc = new Process();
......
$proc->process1($model1Instance);
$proc->process2($model1Instance);

When process1() removes a model from the parent, how can I have it removed in process2()?

Tried/Will try:

1.Method: $model1Instance->seasons()->detach($season); but got: Call to undefined method Illuminate\Database\Query\Builder::detach()

2.Another class I could make another simple class to store these but I do not think it is okay, although I could then set filtered seasons but still have to use Model1 instance:

class Model1Copy {
    private $seasons;
    public function __construct($seasons) {
        $this->seasons = $seasons;
    }
}
  1. Fatal when tried:

    public function process1($model1Instance) {

    for($model1Instance->seasons() as $season) {
        if(//whatever//) {
            $season->delete();
        } else {
        $childs[]=$season;
        }
    }
    $model1Instance->seasons = $childs
    

    }

  2. Would be to make my own repositories to skip the ORM`s behavior, but it is frustrating because I have to rewrite all queries just to remove an instance...

回答1:

To delete hasMany records with condition:

$model1Instance->seasons()->where('condition', 'met')->delete();

To delete all:

$model1Instance->seasons()->delete();


回答2:

$model->seasons() returns the relation, whereas $model->seasons returns the Collection of Season mapped to the model. Try the following.

public function process1($model1Instance) {

    // Iterate over the collection
    for($model1Instance->seasons as $season) {
        if(condition) {
            $model1Instance->seasons()->detach($season); 
            $season->delete();
        }
    }

    $model1Instance->save();
}

Also, you're iterating all seasons of all models, and deleting seasons that satisfy some condition. Wouldn't it be more efficient if you destroy all seasons in one go. Something like the following:

$seasons = Season::where(condition)->get();
Season::destroy($seasons);


回答3:

Try this

public function process1($model1Instance) {

    // Iterate over the collection
    for($model1Instance->seasons as $season) {
        if(condition) {
            $season->delete();
        }
    }

    $model1Instance->save();
}