It's very common to see new Yii users confusing the relations HAS_ONE
and BELONGS_TO
, and getting it wrong means you won't get proper values back. And though we'll talk about HAS_MANY
as well, we're specifically omitting the MANY_MANY
relation because it's a whole different animal.
Both BELONGS_TO
and HAS_ONE
are about linking two models together, and sound like the same thing, but they link in essentially opposite directions. Let's illustrate with three simple tables, each of which has a primary key (id
), and a number of linking fields (user_id
) that reference the User table.
~~~
USER table
- id
- name
POST table
- id
- user_id REFERENCES User.id
- content
PROFILE table
- id
- user_id REFERENCES User.id
- profile_info
**KEY POINT**: A `BELONGS_TO` relation says that a field in **this** model points to the primary key in **another** model; in this case, _the current model owns the linking field_.
KEY POINT: A HAS_ONE
relation says that some other model has a linking field pointing to this model's primary key; in this case, the related model owns the linking field.
We can thik that a PARENT table will be the one that doesn't have a foreign key, and a CHILD table as the one who "depends" on the parent table, that is, it has a foreign key.
Given that, a CHILD BELONGS_TO a PARENT and a PARENT HAS_ONE CHILD.
Let's put these in context (numbered for reference)
// Post model relations
1. 'user' => array(self::BELONGS_TO, 'User', 'user_id'),
// Post belongs_to a user, because it is a child table.
// Profile model relations
2. 'user' => array(self::BELONGS_TO, 'User', 'user_id'),
// Profile belongs_to a user, because it is a child table.
// User model relations
3. 'posts' => array(self::HAS_MANY, 'Post', 'user_id'),
// User has_many posts, because User is a parent table.
4. 'profile' => array(self::HAS_ONE, 'Profile', 'user_id'),
// User has_one profile, because User is a parent table.
Relations 1 has the linking field user_id
in this model, pointing to the primary key of the related model User
. Likewise with relation #2.
Relations 3 and 4 are essentially the same thing as each other: the linking field user_id
is not in this model, but in the related model, and the primary key involved is in this model (User
). The difference is that HAS_MANY
returns an array of possibly multiple objects, while HAS_ONE
returns a single object.
HAS_ONE
is just a special case of HAS_MANY
, and the circumstances where HAS_ONE
makes sense are far more limited than HAS_MANY
and BELONGS_TO
.
Weird example
USER table
- id
- name
- status_id REFERENCES status.id
STATUS table
- id
- name
Here one would think in human terms that a USER HAS_ONE STATUS. But that doesn't work. As you see, the USER is in fact a "child" table of STATUS, because it is referencing it, it depends on it. So the relations would be:
// User model relations
1. 'status' => array(self::BELONGS_TO, 'Status', 'status_id'),
// User belongs_to a status, because it is a child table.
// Status model relations
2. 'users' => array(self::HAS_MANY, 'User', 'status_id'),
// Status has_many users, because it is a parent table.
Some points to remember:
- When defining one of these relations, you don't ever name the primary key; Yii figures it out from the DB schema
BELONGS_TO
is where this model owns the linking fieldBELONGS_TO
references the related model's primary keyHAS_ONE
/HAS_MANY
is where the related model owns the linking fieldHAS_ONE
/HAS_MANY
reference this model's primary key- If you define a
BELONGS_TO
relation in one model, you probably want an associatedHAS_MANY
relation in its related mode - You probably don't really want
HAS_ONE
ever
Very Helpful
This post was especially helpful in debugging issues with my application's model structure. SJFriedl, very good work.
HAS_ONE = PK, FK
As my point of view, HAS_ONE relation stands for column which is PK, FK in referenced table. Example:
_tbl_profile.user_id (PK, FK) references -> tbluser.id
user HAS_ONE profile and profile BELONGS_TO user
Please tell me if I'm wrong.
Great article :-)
Confused about schema for profile table
Although it's not explicit in the article, I would think that the relation from profile to user would be an identifying relation. Yet the schema has the relation as non-identifying (a profile can exist without a user). And it allows more than one profile per user. The Yii logic overlaid upon the schema prevents this and appears to make the profile table's id column superflous.
I think ManInTheBox was saying the same in #5030.
Very helpful
Thanks, this is exactly what I needed to read to solve my problems.
Very useful
Short, concise, clear and to the point. I like it! :)
The mentioned points should definitely go into the official guide. AFAIK its not there and it should (the difference between belongs_to and has_one)
LIMIT
sorry my english is bad :(
now.. a few Relations, given how by difference Relations to limit
exp;
parent = HAS_MANY = limit 5
children = BELONGS_TO = limit 4
notes = HAS_MANY = limit 10
etc...
Key Point is highlight
I like the key point summary part, which is very helpful for Yii beginners. Thanks a lot.
Has Many with limit
return array( 'posts' => array(self::HAS_MANY, 'Post', 'P_ID','limit'=>'5'), );
Weird example
About the Weird example.
I had seen this way before, but how it possible to Create a user row later. let say, get the status_id, that wwill create the record on Status Table then retrieve on user row added?
Another example of this approach.
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.