可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have two tables with field username
in both. How i can specify field name for both local and foreign table?
I want CakePHP will do something like
ON (`T1`.`username` = `T2`.`username`)`
in result.
Without any changes tables will be joined with following condition:
ON (`T1`.`id` = `T2`.`t1_id`)`
Setting 'foreign_key' = 'username'
property is not enough because it will produce query like this:
ON (`t1`.`id` = `t2`.`username`)`
I have two solutions.
First one is use 'join' property and join table on the fly. In such case i can set both local and foreign field. But if i need to join more tables to that one, joined manually, i can't use contain anymore i need to write following joins manually even if that associations was set correctly.
So i need to write long join definitions every time instead just use 'contain' => array('T1', 'T2', 'T3')
Second is to set 'primary_key' of table to corresponding field. It can be done in model file or in runtime. In my case it can not be done in model because that table also have "correct" association by its 'id'
field.
Setup it runtime is the case but i dislike it because it's not obvious and looks like a hack.
When i ask this question i thought i missing something obvious but now i understand that CakePHP just can't do that. So i started a bounty hoping that somebody share solution. If not i will try to read cake sources and redefine model some of method to add ability to define local field near the 'foreign_key'
in association definition.
回答1:
ForeignKey false
To have an association which does not use the primary key of the related model in join conditions - the standard way to do that would be to use 'foreignKey' => false
.
I.e. whereas this association:
class Comment extends AppModel {
public $belongsTo = array(
'Profile' => array(
)
);
}
Will generate this sql:
SELECT ... LEFT JOIN profiles on ON (Profile.id = Comment.profile_id)
Specifying that a foreignKey isn't to be used like so:
class Comment extends AppModel {
public $belongsTo = array(
'Profile' => array(
'foreignKey' => false
)
);
}
Will produce this (invalid) sql:
SELECT ... LEFT JOIN profiles on ON ()
From this point, the desired conditions can be specified using the conditions array key:
class Comment extends AppModel {
public $belongsTo = array(
'Profile' => array(
'foreignKey' => false,
'conditions' => array(
'Comment.username = Profile.username'
),
)
);
}
(Note that the conditions are defined as a string) resulting in:
SELECT ... LEFT JOIN profiles on ON (Comment.username = Profile.username)
回答2:
Update:
Just specify that you don't want to use a foreignKey, then specify the conditions (all within the association:
'foreignKey' => false
and 'conditions' => 'Comment.username = User.username'
PS - probably a good idea moving forward to try not to be rude to the people helping you.
This is very clearly defined in the CakePHP book: http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasmany
class User extends AppModel {
public $hasMany = array(
'Comment' => array(
'className' => 'Comment',
'foreignKey' => 'user_id', // <---- THIS HERE you can define the foreign_key
'conditions' => array('Comment.status' => '1'),
'order' => 'Comment.created DESC',
'limit' => '5',
'dependent' => true
)
);
}
What is a Foreign Key?:
In the context of relational databases, a foreign key is
a field in one table that uniquely identifies a row of another table.
回答3:
Just a workaround that should work for your hasMany relationship when you want to retrieve a User and all his Comments
class User extends AppModel {
public $hasMany = array(
'Comment' => array(
'finderQuery' => 'SELECT * FROM comments Comment
LEFT JOIN users User
ON Comment.username = User.username
WHERE User.id = {__CakeID__}'
)
);
}
Hope it helps
回答4:
I struggled with this exact problem for days and the solution that I found (not clearly addressed above) is: The hasMany
must have 'foreignKey' => false
while the belongsTo
MUST ALSO have the 'foreignKey' => false
and have the 'conditions' => 'Comment.username = User.username'
. With the conditions
as a string not assoc array. Like so:
// Profile
public $hasMany = array(
'Comment' => array(
'foreignKey' => false,
)
);
// Comment
public $belongsTo = array(
'Profile' => array(
'foreignKey' => false,
'conditions' => array('Profile.username = Comment.username')
)
);
回答5:
public $hasMany = array(
'Comment' => array(
'className' => 'T1',
'foreignKey' => 'username',
'dependent' => true
)
);
Note that dependent true would delete all the T1's when T2's were deleted from within cake.