Getting multiple relationships in Eloquent

2019-09-09 20:33发布

问题:

Fundamental misunderstanding of model in Eloquent (Outside of Laravel)

My previous question that ceejayoz helped point me in the right direction for, but that has led me to what is basically a new question.

I'm working on a simple chemical tracking database and have it structured with a chemicals table which tracks most of the info but I have a few fields that started out as Enums but I realized that would not work for. There are now separate tables for company, room, and location. All of these additional tables include just an id and the field so company is:

1 | 'FISHER'

2 | 'BDH'

etc.

I can do

$company = chemical::find(4)->company;

for example and that will give me the name of the company for that chemical, but what I am trying to do is display a table with all of the information in each chemical, as well as the associated company name, room, location. I am just not sure as to how to accomplish this.

How would I even get the associated company for all the chemicals?

$chemicals = company::all()->company;

Does not work and I can see why.

$chemicals = chemical::all();   

foreach($chemicals as $chem) {
    echo $chem->company . "<br />";
}  

Will get me the associated companies and that's great, but then where do I go from there in terms of the comprehensive table?

回答1:

You don't specify how your tables company, room, and location are related to chemicals. However, if they are all belongsTo type relationships, then I believe you are looking for Eager Loading:

Eloquent can "eager load" relationships at the time you query the parent model. Eager loading alleviates the N + 1 query problem.

To eager-load multiple relationships, you can do something like:

$chemicals = chemical::with('company', 'room', 'location')->get();

If you are using a templating engine like Twig or Blade (which hopefully you are), you can then pass your $chemicals directly to the template. Otherwise, you can iterate through $chemicals as you demonstrated in your question:

echo "<table><thead><tr>
      <th>Chemical ID</th>
      <th>Chemical Name</th>
      <th>Company Name</th>
      <th>Location Name</th>
      <th>Room Name</th>
      </tr></thead><tbody>";

foreach($chemicals as $chem) {
    echo "<tr><td>{$chem->id}</td>
              <td>{$chem->name}</td>
              <td>{$chem->company->name}</td>
              <td>{$chem->location->name}</td>
              <td>{$chem->room->name}</td>
          </tr>";
}
echo "</tbody></table>";

Please also notice that the convention in Eloquent is to capitalize your model class names (Chemicals, not chemicals).



回答2:

The question is a little unclear, but for a table of chemicals that includes their company data, you'd do something along these lines. In your controller:

// we use with() to "eager load" the company data
// this makes the following line execute two queries
// without the with(), our Blade template will make a query
// to the companies table for EVERY row in the table

// if you have hundreds/thousands of chemicals, you'll
// want to consider paginate() instead of get() too

$chemicals = Chemical::with('company')->get();

return view('your.view')->withChemicals($chemicals);

In your Blade view, you can access all of each chemical's company's properties:

<table>
  @foreach($chemicals as $chemical)
    <tr>
      <td>{{ $chemical->name }}</td>
      <td>{{ $chemical->company->name }}</td>
    </tr>
  @endforeach
</table>


回答3:

I guess, what you asked for, is this:

chemicals: id, company (ENUM), ...

now you extracted data to

companies: id, name (same as ENUM in chemicals previously)

If that's the case, then you can do 2 things:

  1. create ordinary relationship with id and company_id beings the keys and update your chemicals table to add appropriate company_id values depending on their company enum/string value, then drop company column. It may require more adjustments, eg. everywhere where you called chemical->company to get the company name (becomes chemical->company->name)

  2. create a relationship based on the chemicals.company and companies.name fields.

Definitely the first option is better in the long run.