【问题标题】:How to update a pivot table using Eloquent in laravel 5如何在 laravel 5 中使用 Eloquent 更新数据透视表
【发布时间】:2016-02-06 05:58:03
【问题描述】:

我是 laravel 的新手。我正在开发一个 laravel 5 应用程序,但我被困在这里。我有 2 个这样的模型:

class Message extends Eloquent{

    public function user()
    {
        return $this->belongsTo('App\User', 'from');
    }

    public function users()
    {
        return $this->belongsToMany('App\User')->withPivot('status');
    }
}

class User extends Eloquent {

    public function messages()
    {
        return $this->hasMany('App\Message', 'from');
    }

    public function receive_messages() {
        return $this->belongsToMany('App\Message')->withPivot('status');
    }
}

Message 和 User 之间存在多对多关系,为我提供了这样的数据透视表:

Table Name: message_user
Colums:
message_id
user_id
status

我有一个这样的 SQL 查询:

update message_user
set status = 1
where user_id = 4 and message_id in (select id from messages where message_id = 123)

如何将此查询转换为 laravel 等效项?

【问题讨论】:

  • 哥们from是什么意思?
  • 外键@Mohamed
  • dude 第二个参数是连词表名,在你的例子中它应该是 'message_user' , usermessages 的总权利关系型号:return $this->hasMany('App\Message\,'message_user','user_id','message_id');
  • 不,伙计。你错过了重点。查看 laravel 文档。这可以提供帮助:laravel.com/docs/5.1/eloquent-relationships#many-to-many
  • 感谢您的投入。用户可以创建 1 条或多条消息。一条消息可以被 1 个或多个用户接收。一个用户可以收到 0 条或更多条消息。

标签: mysql laravel laravel-5 eloquent


【解决方案1】:

您可以使用one of these two functionssync() attach(),简而言之,Sync 将获取数组作为其第一个参数并将其与数据透视表同步(删除并添加在您的array) 这意味着如果您在联结表中获得了 3,2,1 的值,并与 3,4,2 的值同步传递,同步将自动删除值 1 并为您添加值 4。其中 Attach 将采用单个 ID 值

GIST:如果您想向连接表添加额外的值,请将其作为第二个参数传递给 sync(),如下所示:

$message = Messages::find(123);
$user = User::find(4);

// using attach() for single message
$user->message()->attach($message->id, [
    'status' => 1
]);



$message2 = Messages::find(456); // for testing

// using sync() for multiple messages
$user->message()->sync([
    $message->id => [
        'status' => 1
    ],
    $message2->id => [
        'status' => 1
    ],
]);

【讨论】:

  • 感谢您的意见@Mohamed。同步对我没用。
  • @FokwaBest dude 根据您上面的评论,您只想要多对多关系,因此您的雄辩关系存在误导,如果您愿意,我可以更新我的答案并写下正确的关系,然后sync() 可以工作:)
  • dude 实际上当用户创建消息时,存储在消息表中。数据透视表只记录 message_id 和收件人 ($user_id)。它现在工作得很好,但无论如何我很想看看你的方法。
  • 谢谢@MohamedKawsara!我只想注意sync() 方法调用中最重要的false 标志。因为如果没有通过,所有与当前 $message->id 不同的其他记录都将被分离。另外,请注意,当我们附加时,方法调用是attach( $id, ['attr1' => 'val1']),但在sync() 调用我们有sync([$id **=>** ['attr1' => 'val1']]);
【解决方案2】:

这是一个如何更新数据透视表列的小例子

    $query = Classes::query();
    $query = $query->with('trainees')
                   ->where('user_id', Auth::id())
                   ->find($input['classId']);

    foreach ($query->trainees as $trainee) {
       $trainee->pivot->status = 1 //your column;
       $trainee->pivot->save();
    }

注意:确保你的关系数据必须在一个数组中 希望它对你有帮助:) 快乐编码

【讨论】:

    【解决方案3】:

    Laravel 5.8

    首先,通过将withPivot 方法链接到您的belongsToMany 来允许您的数据透视列可搜索

    从我自己的代码中复制以节省时间

    // I have 3 columns in my Pivot table which I use in a many-to-many and one-to-many-through scenarios
    
    $task = $user->goalobjectives()->where(['goal_objective_id'=>$goal_objective_id,'goal_obj_add_id'=>$goal_obj_add_id])->first(); //get the first record
    
    $task->pivot->goal_objective_id = $new; //change your col to a new value
    
    $task->pivot->save(); //save
    

    需要注意的是,您的数据透视表需要有一个主要的 'id' 键。

    如果你不想这样,那么你可以尝试以下方法:

    $tasks=$user->posts()->where(['posts_id'=>$posts_id,'expires'=>true])->get()->pluck('id'); // get a collection of your pivot table data tied to this user
    
    $key=join(",",array_keys($tasks->toArray(),$valueYouWantToRemove));
    
    $tasks->splice($key,1,$newValueYouWantToInsert);
    
    $c = array_fill(0,$tasks->count(),['expires'=>true]); //make an array containing your pivot data
    
    $newArray=$tasks->combine($c) //combine the 2 arrays as keys and values
    
    $user->posts()->sync($newArray); //your pivot table now contains only the values you want
    

    7 月 4 日更新更新至以上 sn-p。

    //Ideally, you should do a check see if this user is new
    //and if he already has data saved in the junction table
    //or are we working with a brand new user
    
    $count = $user->goalobjectives->where('pivot.goal_obj_add_id',$request->record)->count();
    
    //if true, we retrieve all the ids in the junction table 
    //where the additional pivot column matches that which we want to update
    
    if($count) {
    
    $ids = $user->goalobjectives->where('pivot.goal_obj_add_id',$request->record)->pluck('id');
    
    //convert to array
    
    $exists = $ids->toArray();
    
    //if user exists and both saved and input data are exactly the same
    //there is no need
    //to update and we redirect user back
    
    if(array_sum($inputArray) == array_sum($exists)) {
    
    //redirect user back
    
    }
    
    //else we update junction table with a private function
    //called 'attachToUser'
    
    $res = $this->attachToUser($user, $inputArray, $ids, $request->record);
    
    }//end if
    
    elseif(!$count) {
    
    //we are working with a new user
    //we build an array. The third pivot column must have equal rows as
    //user input array
    
    $fill = array_fill(0,count($inputArray),['goal_obj_add_id'=>$request->record]);
    
    //combine third pivot column with user input
    
    $new = array_combine($inputArray,$fill);
    
    //junction table updated with 'user_id','goal_objective_id','goal_obj_add_id'
    
    $res = $user->goalobjectives()->attach($new);
    
    //redirect user if success
    
    }
    
    //our private function which takes care of updating the pivot table
    
    private function attachToUser(User $user, $userData, $storedData, $record) {
    
    //find the saved data which must not be deleted using intersect method
    
    $intersect = $storedData->intersect($userData);
    
    if($intersect->count()) {
    
    //we reject any data from the user input that already exists in the database
    
    $extra = collect($userData)->reject(function($value,$key)use($intersect){
    
    return in_array($value,$intersect->toArray());
    
    });
    
    //merge the old and new data
    
    $merge = $intersect->merge($extra);
    
    //same as above we build a new input array
    
    $recArray = array_fill(0,$merge->count(),['goal_obj_add_id'=>$record]);
    
    //same as above, combine them and form a new array
    
    $new = $merge->combine($recArray);
    
    //our new array now contains old data that was originally saved
    //so we must remove old data linked to this user
    // and the pivot record to prevent duplicates
    
    $storedArray = $storedData->toArray();
    
    $user->goalobjectives()->wherePivot('goal_obj_add_id',$record)->detach($storedArray);
    
    //this will save the new array without detaching
    //other data previously saved by this user
    
    $res = $user->goalobjectives()->wherePivot('goal_obj_add_id',$record)->syncWithoutDetaching($new);
    
    }//end if
    
    //we are not working with a new user
    //but input array is totally different from saved data
    //meaning its new data
    
    elseif(!$intersect->count()) {
    
    $recArray = array_fill(0,count($userData),['goal_obj_add_id'=>$record]);
    
    $new = $storedData->combine($recArray);
    
    $res = $user->goalobjectives()->wherePivot('goal_obj_add_id',$record)->syncWithoutDetaching($new);
    
    }
    
    //none of the above we return false
    
    return !!$res;
    
    }//end attachToUser function
    

    这适用于没有主要自动增量 ID 的数据透视表。如果没有自动增量 ID,用户无法通过直接访问来更新、插入、删除数据透视表中的任何行。

    【讨论】:

      【解决方案4】:

      下面的代码解决了我的问题:

      $messages  = Message::where('message_id', $id)->get();
      foreach($messages as $message)
         $message->users()->updateExistingPivot($user, array('status' => 1), false);
      

      【讨论】:

      • 我能知道false是什么意思吗?
      • @MuhammadDyasYaskur 确定是否要更新 updated_at 列时间戳
      【解决方案5】:

      要更新您的数据透视表,您可以使用 updateExistingPivot 方法。

      【讨论】:

      • 谢谢@Babar。您能否添加任何示例代码,说明我如何使用该方法与帖子中的查询一起使用。
      • 你可以在laravel.com/docs/5.0/eloquent#working-with-pivot-tables查看文档 参考代码是 User::find(1)->roles()->updateExistingPivot($roleId, $attributes);
      猜你喜欢
      • 2015-12-28
      • 1970-01-01
      • 2016-03-09
      • 1970-01-01
      • 2016-02-21
      • 1970-01-01
      • 2017-05-05
      • 1970-01-01
      • 2021-10-03
      相关资源
      最近更新 更多