Optimisez Laravel Join pour récupérer toutes les données sur une seule ligne sans dupliquer les tables
P粉410239819
P粉410239819 2024-01-16 11:40:46
0
1
485

J'ai 4 tables MySQL, utilisant PHP et Laravel 7

  1. Membres
  2. Déduction
  3. Paiement
  4. Déductions de paiement

Maintenant, je souhaite afficher en continu le paiement unique de chaque membre et toutes les autres déductions. (En supposant qu'une personne n'a qu'un seul paiement)

La structure de la base de données est la suivante

C'est le tableau HTML que je souhaite afficher

C'est la requête que j'utilise, mais elle duplique les données.

$payments = Payment::leftJoin('members', 'payments.member_id', '=', 'members.id')
        ->leftJoin('payment_deductions', 'payments.id', '=', 'payment_deductions.payment_id')
        ->leftJoin('deductions', 'payment_deductions.deduction_id', '=', 'deductions.id')
        ->select(
            'members.*',
            'payment_deductions.*',
        )
        ->orderBy("member_id", "ASC")
        ->get()->toArray();

Le tableau résultant répète chaque membre en fonction de sa dérivation.

Existe-t-il un moyen d'améliorer ces données ? Quelque chose comme un tableau imbriqué de déductions pour chaque membre ?

C'est le modèle

Membre

namespace App;

    use IlluminateDatabaseEloquentModel;
    use CarbonCarbon;

    class Member extends Model
    {
        protected $fillable = [
            'full_name',
            'email',
            'created_by',
        ];
    }

Paiement

namespace App;

    use IlluminateDatabaseEloquentModel;

    class Payment extends Model
    {
        protected $fillable = [
            'member_id',
            'total_amount',
            'payable_amount',
            'created_by',
        ];

        public function deductions() {
           return $this->belongsToMany(Deduction::class,'payment_deductions')->withTimestamps();
        }
    }

Déduction

namespace App;

    use IlluminateDatabaseEloquentModel;

    class Deduction extends Model
    {
        protected $fillable = [
        'title',
        'priority',
        'created_by',
        ];
    }


P粉410239819
P粉410239819

répondre à tous(1)
P粉239089443

Vous êtes très proche et sur la bonne voie lors de la construction du modèle, ce qui vous manque, c'est comment charger les relations sans créer une autre requête, si vous regardez le contrôleur, vous verrez la manière standard de charger les relations à l'intérieur. J'espère que c'est un meilleur concept pour répondre à vos préoccupations.

Pour référence : https://laravel.com/docs/9.x/eloquent-relationships#lazy-eager-loading

Faire cela évitera également de futurs problèmes N+1, voir Quel est le "problème de sélection N+1" dans ORM (Object Relational Mapping) ? N+1 问题,请参阅什么是 ORM(对象关系映射)中的“N+1 选择问题”? 有关 N+1 Détails sur N+1

Modèle de membre

public class Member extends Model
{
    protected $fillable = [
       'full_name',
       'email',
       'created_by',
    ];
        
    public function payments(){
        return $this->hasMany(Payment::class);
    }
}

Mode de paiement

public class Payment extends Model
{
    protected $fillable = [
       'member_id',
       'total_amount',
       'payable_amount',
       'created_by',
    ];
        
    public function member(){
        return $this->belongsTo(Member::class);
    }

    public function deductions() {
        return $this->belongsToMany(Deduction::class,'payment_deductions')->withTimestamps();
    }
}

Modèle de déduction

public class Deduction extends Model
{
    protected $fillable = [
       'title',
       'priority',
       'created_by',
    ];
        
    public function payments() {
        return $this->belongsToMany(Payment::class,'payment_deductions')->withTimestamps();
    }
}

Contrôleur membre :

/**
 * Show the specified model.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  Member $member
 * @return \Illuminate\Http\Response
 */
public function show(Request $request, Member $member){
    // This will load all of the inner relationships in a single query.
    $member->load('payments.deductions');
        
    //Assign the loaded payments to be used
    $payments = $member->payments;
        
    /* 
        You can acess the payments -> deductions in a foreach loop, in php or blade
        foreach($payments->deductions as $deduction){
           //$deduction->id   
        }
    */  
        
    return view('sampleView', compact('member', 'payments'));
}
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal