admin管理员组

文章数量:1332107

In Laravel Eloquent, I am using select to get specific columns only in a collection:

$tickets = Tickets
           ::select('id', 'title', 'date') // so only these columns
           ->limit(100)
           ->get();

but I also have a custom attribute in the "Ticket" model that uses different columns:

public function getStatusAttribute() {
    if ($this->payment == $this->total & $this->active) {
        return "paid";
    } else {
        return "unpaid";
    }
}

then when doing

foreach ($tickets as $ticket) {
    echo $ticket->id 
    . $ticket->title
    . $ticket->date
    . $ticket->status // <- custom attribute
    ;
}

as I tell query to only select 'id', 'title', 'date', at what point Laravel gets additional columns from database (specifically the 'payment', 'total', 'active')? Does it runs additional queries for each row?

I only see main query (without columns from custom attribute being selected), when trying to log them either with dump(DB::getQueryLog()); or directly in MySQL:

SET GLOBAL log_output = "FILE";
SET GLOBAL general_log_file = "c:/AAA/logfile.log";
SET GLOBAL general_log = 'ON';

So I do not understand at what point Laravel gets additional columns from the database? My concern is to have 1 query and not 100.

In Laravel Eloquent, I am using select to get specific columns only in a collection:

$tickets = Tickets
           ::select('id', 'title', 'date') // so only these columns
           ->limit(100)
           ->get();

but I also have a custom attribute in the "Ticket" model that uses different columns:

public function getStatusAttribute() {
    if ($this->payment == $this->total & $this->active) {
        return "paid";
    } else {
        return "unpaid";
    }
}

then when doing

foreach ($tickets as $ticket) {
    echo $ticket->id 
    . $ticket->title
    . $ticket->date
    . $ticket->status // <- custom attribute
    ;
}

as I tell query to only select 'id', 'title', 'date', at what point Laravel gets additional columns from database (specifically the 'payment', 'total', 'active')? Does it runs additional queries for each row?

I only see main query (without columns from custom attribute being selected), when trying to log them either with dump(DB::getQueryLog()); or directly in MySQL:

SET GLOBAL log_output = "FILE";
SET GLOBAL general_log_file = "c:/AAA/logfile.log";
SET GLOBAL general_log = 'ON';

So I do not understand at what point Laravel gets additional columns from the database? My concern is to have 1 query and not 100.

Share Improve this question asked Nov 26, 2024 at 22:48 LannalinaLannalina 31 bronze badge 1
  • Just advice - if this attribute MATTER - check real fields for null and throw exception on null. Queries will mot perform as answered below. – Maksim Commented Nov 27, 2024 at 1:13
Add a comment  | 

2 Answers 2

Reset to default 0

The status attribute is never queried from the DB. The value is calculated after the query is run when you request the value using $ticket->status or when the instance of the model is serialised.

If you have retrieved your instance using your query builder code:

    Tickets::select('id', 'title', 'date') // so only these columns
       ->limit(100)
       ->get();

Then I would expect your getStatusAttribute to return "paid" but you need to understand why:

The query will result in an instance where

$this->payment is NULL

$this->total is NULL

and $this->active is NULL

Because you're not getting those values from the database.

When you call $this->payment == $this->total & $this->active You're saying NULL == NULL & NULL Note: Be careful with your logic here as NULL & NULL will evaluate to 0 whereas NULL && NULL will evaluate to false

Therefore you need to either be more defensive in your getStatusAttribute logic. You could consider returning NULL if the required columns are all NULL but you probably want to make sure those values are always queried.

$tickets = Tickets::select('id', 'title', 'date', 'payment', 'total', 'active')
    ->limit(100)
    ->get();

The above would do the job but the overhead of querying columns you don't explicitly need is negligible so you could just drop the select entirely and use:

$tickets = Tickets::limit(100)
    ->get();

If there are values in there you want to prevent the model showing when serialised I would recommend using the Eloquent Model's "hidden" property

hope my solution solves your problem. To ensure the status attribute works correctly, modify your query to include the columns needed for the accessor:y and avoid additional queries.

$tickets = Tickets::select('id', 'title', 'date', 'payment', 'total', 'active')
    ->limit(100)
    ->get();

This way, all the necessary data for the custom attribute is fetched in the initial query.

Thanks

本文标签: