Maison  >  Questions et réponses  >  le corps du texte

Optimisez Laravel Join pour récupérer toutes les données sur une seule ligne sans dupliquer les tables

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粉410239819P粉410239819251 Il y a quelques jours413

répondre à tous(1)je répondrai

  • P粉239089443

    P粉2390894432024-01-17 09:20:05

    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< /p>

    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'));
    }

    répondre
    0
  • Annulerrépondre