4

在我的用户模型中,我有以下关系:

public $hasAndBelongsToMany = array(
        'User'=>array(
            'className'              => 'User',
            'joinTable'              => 'friends',
            'with'                   => 'Friend',
            'foreignKey'             => 'user_id',
            'associationForeignKey'  => 'friend_id'
        )
);

它将用户链接到用户作为朋友。但是,当我对单个用户执行某些操作时,例如更改密码或编辑用户详细信息(与朋友无关),它将开始在朋友表中执行操作,例如删除所有现有记录,然后添加空数据行。 .

我是不是把关系搞错了?命名是否应该不同,这样我在处理$this->User它时就不会触动朋友?

编辑:自从发布此问题以来,我已将 user_id 和friend_id 更改为 user1_id 和 user2_id 以防止 Cake 通过假设它们是主键或 nIcO 下面解释的任何内容来对字段进行任何自动操作。但是同样的问题还是会发生!

4

6 回答 6

2

我强烈建议使用真正的 Friends 模型进行此操作。像这样设置它:

User hasMany FriendList
User hasMany FriendOf (alias of FriendList)

FriendList belongsTo User
FriendList belongsTo Friend (alias of User)

示例代码:

Table definitions (skeleton):

users:
  id
  name

friend_lists:
  id
  user_id
  friend_id

Model Definitions:

class User extends AppModel {
  var $hasMany = array(
    'FriendList',
    'FriendOf' => array(
      'className' => 'FriendList',
      'foreignKey' => 'friend_id'
    )
  );
}

class FriendList extends AppModel {
  var $belongsTo = array(
    'User',
    'Friend' => array(
      'className' => 'User',
      'foreignKey' => 'friend_id'
     )
  );
}
于 2012-12-20T21:07:51.733 回答
0

您的连接表被调用friends并使用名为 的模型Friend。通过查看 HABTM 关系声明,该friends表似乎包含一个名为的字段user_id和一个名为 的字段friend_id

在表中拥有一个friend_id字段friends就像在表中拥有一个user_id字段users,您可能不会这样做。而且我猜 Cake 不喜欢它,因为friend_idCake 将其视为指向另一个名为Friend.

无论如何,使用 HABTM 关系处理同一张表之间的 HABTM 并不容易(参见HABTM with self 需要 2x 连接表中的行?),您可能应该改用连接模型(参见http://book.cakephp.org/ 2.0/en/models/associations-linking-models-together.html#hasmany-through-the-join-model )

于 2012-12-18T21:47:00.420 回答
0

不要创建与 hasAndBelongsToMany 关系中使用的模型具有相同别名/名称的模型。这让我对 CakePHP 感到头疼。

例如;

我有一个名为“公司”的模型,HABTM“用户”记录。所以我的数据库中有一个名为“companyies_users”的表。

您可能很想在您的公司模型中做这样的事情。

var $hasAndBelongsToMany = array(
    'User'=>array('with'=>'CompanyUser')
);

然后创建一个“CompanyUser”模型,因为你想在关联中存储额外的数据。

不要这样做。我不知道为什么,但 Cake 无法预测它何时会自动创建一个名为“CompanyUser”的模型以及何时会实际加载您创建的 PHP 文件。

最好在您的模型中定义 HABTM 以使用默认关联,然后从表中创建一个不同名称的模型,并使用它来处理记录。这确保 CakePHP 也将使用自动生成的模型并正常工作。

因此,在我的示例中,我创建了一个名为“Members”的模型,将“useTable”变量设置为“companies_users”。

现在我知道当我使用“公司”模型时,CakePHP 会正确处理 HABTM,如果我需要访问那些连接记录,那么我会使用“成员”模型。

使用“with”选项的风险是你永远不知道 CakePHP 什么时候会失败,并自动生成模式。在这种情况下,您的任何回调或行为都不会发生。

编辑:

更直接地回答这个问题。

修改 User.php 模型文件,以便 HABTM 使用更多默认值。

 public $hasAndBelongsToMany = array('Friend');

确保您没有为连接表定义 UserFriend.php 模型文件。如果您需要修改连接表,请使用具有不同别名的模型指向数据库中的该表。

于 2012-12-20T21:17:27.117 回答
0

我猜你的问题是由于错误地声明了关联引起的。试试这个:

public $hasAndBelongsToMany = array(
        'Friend'=>array(
            'className'              => 'Friend',
            'joinTable'              => 'friends',
            'foreignKey'             => 'user_id',
            'associationForeignKey'  => 'friend_id'
        )
);
于 2012-12-24T13:33:59.660 回答
0

有几种方法可以实现友谊关联,因为友谊中有两个方向。可以说用户 A 是用户 B 的好友,也可以说用户 B 是用户 A 的好友。

当一个人在数据库中建立友谊时。您必须在连接表中创建两条记录来表示双向的这种友谊(假设您想要双向)。

这涵盖了方向的概念。

您可能会遇到记录消失的问题,因为默认情况下,CakePHP 会在记录更新时擦除记录的所有连接数据行。查看 HABTM 上“唯一”选项的描述。

unique:如果为true(默认值),更新记录时,蛋糕将首先删除外键表中现有的关系记录,然后再插入新的关系记录。所以更新时需要再次传递已有的关联。

这意味着您必须在更新记录时始终包含 HABTM 数据。否则,这些记录将被删除,并根据通过的内容进行更新。

现在,您可以创建的最基本的友谊设置将涉及两个表。

CREATE TABLE `users` (
   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
   `name` varchar(45) NOT NULL,
   PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE `users_users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(10) unsigned NOT NULL,
  `friend_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `user` (`user_id`),
  KEY `friend` (`friend_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

第一个表'users'将保存我们的用户数据,第二个'users_users'是HABTM连接表。请注意名称,它是 users_users 因为它自己加入。

您仍然需要在 CakePHP 中创建两个模型。

第一个是 User.php,它将描述系统中的用户。我们将主要使用 CakePHP 中的默认值来使其工作。因此,HABTM 只是一行“朋友”。

class User extends AppModel
{
    var $name = 'User';
    var $hasAndBelongsToMany = array(
          'Friend'
    );
}

现在,CakePHP 会抱怨表 users_friends 丢失了。我们需要创建一个 Friend 模型,但将其指向 users 表。

class Friend extends AppModel
{
    var $name = 'Friend';
    var $useTable = 'users';
}

现在 CakePHP 将使用 users_users 表作为连接。Friend 模型现在描述了作为朋友的用户。

重要的是要了解您必须在两个方向上创建朋友。当您为用户 A 保存数据时说他/她是用户 B 的朋友,那么您还必须保存用户 B 并说他/她是用户 A 的朋友。否则,只有一个用户将定义好友关系。

这里还有另一个答案,它使用别名定义了友谊的双重方向,但我建议不要实现它,因为它为 CakePHP 增加了您的应用程序可能不需要的额外 SQL 查询工作。当您阅读用户 A 的记录时,您只需要知道他们的朋友是谁,反之则不需要。

您可以创建一个行为,以确保在更新用户记录时友谊是双向的。那会更有效率。

注意:我的代码示例适用于我目前正在使用的 CakePHP 1.3 ,但它在 2.x 中应该可以正常工作。

于 2012-12-24T18:41:26.827 回答
0

根据 Cakephp HABTM 文档,

HABTM 数据被视为一个完整集,每次添加新的数据关联时,数据库中的完整关联行集都会被删除并再次创建,因此您始终需要传递整个数据集以进行保存。

从 2.1 开始,与

您可以设置独特的设置来保持现有的规避在保存操作期间丢失额外的数据。IE,

public $hasAndBelongsToMany = array(
        'User' => array(
                ....
                'unique' => 'keepExisting',
                ....
        ),
);

http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasmany-through

于 2012-12-26T10:46:43.830 回答