John Mellor
John Mellor

Reputation: 2513

Laravel - Really struggling to understand eloquent

I'm fairly new to Laravel having come over from Codeigniter and for the most part I really like it, but I really can't get my head around Eloquent.

If I want to do a simple query like this:

SELECT * FROM site INNER JOIN tweeter ON tweeter.id = site.tweeter_id

I try doing something like this (with a "belongs to"):

$site = Site::with('tweeter')->find($site_id);

But now I have two queries and an IN() which isn't really needed, like so:

SELECT * FROM `site` WHERE `id` = '12' LIMIT 1

SELECT * FROM `tweeter` WHERE `id` IN ('3')

So I try and force a join like so:

$site = Site::join('tweeter', 'tweeter.id', '=', 'site.tweeter_id')->find($site_id);

And now I get an error like so:

SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'id' in where clause is ambiguous

SQL: SELECT * FROM `site` INNER JOIN `tweeter` ON `tweeter`.`id` = `site.tweeter_id` WHERE `id` = ? LIMIT 1

Bindings: array (
  0 => 12,
)

It's obvious where the error is, the where needs to use something like "site.id = ?". But I can't see anyway to make this happen?

So i'm just stuck going back to fluent and using:

DB::table('site')->join('tweeter', 'tweeter.id', '=', 'site.tweeter_id')->where('site.id','=',$site_id)->first()

I guess it's not a massive problem. I would just really like to understand eloquent. I can't help but feel that i'm getting it massively wrong and misunderstanding how it works. Am I missing something? Or does it really have to be used in a very specific way?

I guess my real question is: Is there anyway to make the query I want to make using Eloquent?

Upvotes: 2

Views: 3187

Answers (2)

duality_
duality_

Reputation: 18796

I actually find this behaviour advantageous. Consider this (I'll modify your example). So we have many sites and each has many tweeters. Each site has a lot of info in the DB: many columns, some of them text columns with lots of text / data.

You do the query your way:

SELECT * FROM site INNER JOIN tweeter ON tweeter.id = site.tweeter_id

There are two downsides:

  1. You get lots of redundant data. Each row you get for a tweeter of the same site will have the same site data that you only need once so the communication between PHP and your DB takes longer.
  2. How do you do foreach (tweeter_of_this_site)? I'm guessing you display all the sites in some kind of list and then inside each site you display all of it's tweeters. You'll have to program some custom logic to do that.

Using the ORM approach solves both these issues: it only gets the site data once and it allows you to do this:

foreach ($sites as $site) {
    foreach($site->tweeters as $tweeter) {}
}

What I'm also saying is: don't fight it! I used to be the one that said: why would I ever use an ORM, I can code my own SQL, thank you. Now I'm using it in Laravel and it's great!

Upvotes: 3

Joel Larson
Joel Larson

Reputation: 3074

You can always think of Eloquent as an extension of Fluent.

The problem you're running into is caused by the find() command. It uses id without a table name, which becomes ambiguous.

It's a documented issue: https://github.com/laravel/laravel/issues/1050

To create the command you are seeking, you can do this:

$site = Site::join('tweeter', 'tweeter.id', '=', 'site.tweeter_id')->where('site.id', '=', $site_id)->first($fields);

Of course, your syntax with join()->find() is correct once that issue fix is adopted.

Upvotes: 0

Related Questions