【问题标题】:CakePHP model saving to wrong tableCakePHP 模型保存到错误的表
【发布时间】:2012-12-18 20:53:24
【问题描述】:

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

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 下面解释的任何内容来对字段进行任何自动魔术。但是同样的问题还是会发生!

【问题讨论】:

  • 实际查询是什么样的?您可以使用$log = $this->User->getDataSource()->getLog(false, false); debug($log) 来获取输出
  • 在实际调用 Save 之前,您是否尝试在模型中执行 $this->recursive = 0?如果您从控制器调用 save,在调用 save 方法之前它将是$this->User->recursive=0。如果这不起作用,我明天将尝试在我的系统上设置一个测试场景。 --干杯

标签: php cakephp


【解决方案1】:

我强烈建议使用真正的 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'
     )
  );
}

【讨论】:

  • 您能否举例说明如何在模型中进行设置?
  • 我不确定你的意思...你想要关系定义吗?这些模型就是我刚刚列出的。
  • 根据您上面的结构,我应该创建哪些模型以及其中应该包含哪些模型。
  • 我想这就是你要的:gist.github.com/962c090fa59ec9d225a3
  • 应该使用上面答案中的版本,而不是要点(我在没有登录的情况下愚蠢地创建了它,所以我无法编辑它)。
【解决方案2】:

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

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

这涵盖了方向的概念。

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

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

这意味着您必须在更新记录时始终包含 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 中正常工作。

【讨论】:

  • 友谊模型已经在我的应用中运行良好。那不是我的问题。而是问题在于,当我使用 users 表时,Cake 使用的是 Friend 模型,因为它链接到自身。
  • 在您的问题中,您通过将“类名”定义为“用户”来定义 HABTM 以重用相同的“用户”模型。我不认为这是明智的。其中,我创建了一个新的 Friend.php 模型供 Cake 使用,并将其指向同一张表。我认为这不会造成任何问题。
  • 它破坏了我朋友的东西,但现在我收到以下错误:SELECT Friend.id, Friend.friend_id` FROM db52704_favorr.users AS @987654330 @ WHERE Friend.user_id = '6' AND Friend.status = 1`
  • 所以它在 users 表中查找friend_id,因为我已经告诉 Friend 模型查看 users 表。
  • @Cameron 我有点困惑。对不起。 friend_id 应该只在 users_users 表(连接表)中。
【解决方案3】:

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

friends 表中拥有friend_id 字段就像在users 表中拥有user_id 字段一样,您可能不会这样做。而且我猜Cake 不喜欢它,因为friend_id 被Cake 视为指向另一个 模型Friend 的外键。

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

【讨论】:

  • 我尝试将字段更改为 user1_id 和 user2_id 但同样的问题仍然发生,当我编辑用户详细信息时,它会破坏朋友表中的所有数据。所以这不是问题......
  • 如果可能的话,您能否举例说明我如何使用连接模型来修复这种关系,因为我根本不理解这个问题,而且似乎 Cake 正在做一些我看不到的自动魔法.
【解决方案4】:

不要创建与 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 模型文件。如果您需要修改连接表,请使用具有不同别名的模型指向数据库中的该表。

【讨论】:

  • 你能举一个例子,说明当通过另一个表在同一个表上执行 HABTM 时我将如何解决我的问题?谢谢
  • 试过了,但我得到了错误[MissingTableException] Table friends_users for model FriendsUser was not found in datasource default。更改表名然后导致表朋友丢失的错误......所以它期待两个表?另外,当您说“使用具有不同别名的模型指向数据库中的该表时。”您到底是什么意思?
  • 在一个HABTM中有三个模型。 User 是第一,Friend 是第二,UserFriend 是加入。最后一个应该由 Cake 自动创建。因此,如果您想读/写该表。创建一个名为“Other”的模型,并将 useTable 设置为指向数据库中的“users_friends”。
  • 但我没有朋友的“物理”模型。你能否展示一下我应该拥有什么?什么模型文件以及每个文件中应该包含什么来创建您认为我应该拥有的关系。
  • @Cameron 你用的是什么版本的 CakePHP?
【解决方案5】:

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

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

【讨论】:

    【解决方案6】:

    根据 Cakephp HABTM 文档,

    HABTM 数据被视为一个完整的集合,每次都有一个新数据 关联添加了数据库中完整的关联行集 被删除并再次创建,所以你总是需要通过整个 保存的数据集。

    从 2.1 开始,带有

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-04
      • 1970-01-01
      相关资源
      最近更新 更多