No I don’t think the post table should have a PK to work (I’ve not tested it though). Does the Post model maybe have a defaultScope() set that’s screwing things up for you?
When multiple tables are joined, the same row may appear more than once in the result. In order to avoid populating duplicate data, Yii checks the primary key of populated objects. Object will be dropped if it has the same primary key as an already populated object in the same relation. Obviously, this approach will fail when the table doesn’t have a primary key.
Yes, but he uses findByPk for the User model only. The posts (which is where the problem lies!) are retrieved using the HAS_MANY relation from User to Post, which should retrieve all posts from this user, not just the one.
It doesn’t return many redundant rows, but many redundant fields (or columns if you will).
All rows contain useful information, but all rows contain the same information for the fields in the primary table, and only the fields of the secondary table in the rows are useful.
This is not necessarily a bad thing by the way; like most things in programming the question to the answer what would be better/faster, eager or lazy, is "it depends" [on too many things to explain here].
But that’s just a technicality. So yeah, you’re right
Ok I found the problem. If it was a straight forward User / Post table, most of us would have declared Post with a "id" Primary Key and this HAS_MANY loop problem will never appear.
But no, I was using User/Post as an example of my actual application Site / SiteToModuleMap table. And the old SiteToModuleMap table DO NOT have a Primary Key declared.
The problem is caused by the lack of primary key, hence my HAS_MANY loop only show 1 result. And the workaround is indeed adding this to the model
public function primaryKey()
{
return "id";
// For composite primary key, return an array like the following
// return array('pk1', 'pk2');
}
This is definitely a beginner problem. I will update the title to help others.
Thanks for the effort ScallioXTX and softark!!
from The doc
Performing Relational Query
The simplest way of performing relational query is by reading a relational property of an AR instance. If the property is not accessed previously, a relational query will be initiated, which joins the two related tables and filters with the primary key of the current AR instance. The query result will be saved to the property as instance(s) of the related AR class. This is known as the lazy loading approach, i.e., the relational query is performed only when the related objects are initially accessed. The example below shows how to use this approach:
I’m not sure you are wrong. I have the opposite problem to this poster and I was a) expecting what you thought he was expecting and getting what you thought he’d probably get.