4

私の User モデルでは、次の関係があります。

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 に変更して、nIcO が以下で説明するように、フィールドが主キーまたは何かであると想定して、Cake がフィールドを自動処理しないようにしました。しかし、同じ問題がまだ発生します。

4

6 に答える 6

2

実際のフレンズ モデルでこれを行うことを強くお勧めします。次のように設定します。

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

フレンドシップには 2 つの方向性があるため、フレンドシップ アソシエーションを実装するにはいくつかの方法があります。ユーザー A はユーザー B と友達であると言えますが、ユーザー B はユーザー A と友達でもあります。

人がデータベースで友情を作成するとき。この友情を両方向で表すには、結合テーブルに 2 つのレコードを作成する必要があります (双方向が必要であると仮定します)。

それは方向の概念をカバーしています。

レコードが更新されると、CakePHP はデフォルトでレコードのすべての結合データ行を消去するため、レコードが消えるという問題が発生している可能性があります。HABTM の「unique」オプションの説明を見てください。

unique : true (デフォルト値) の場合、レコードを更新するとき、cake は新しいレコードを挿入する前に、まず外部キー テーブル内の既存の関係レコードを削除します。そのため、更新時に既存の関連付けを再度渡す必要があります。

つまり、レコードを更新するときは常に HABTM データを含める必要があります。そうしないと、それらのレコードは消去され、渡されたもので更新されます。

作成できる最も基本的な友情のセットアップには、2 つのテーブルが含まれます。

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' はユーザー データを保持し、2 番目の 'users_users' は HABTM 結合テーブルです。自分自身に参加しているため、users_users であることに注意してください。

CakePHP で 2 つのモデルを作成する必要があります。

1 つ目は、システム内のユーザーを記述する User.php です。これを機能させるために、CakePHP のほとんどのデフォルトを使用します。したがって、HABTM は 'Friend' という 1 行にすぎません。

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 のレコードを読み取る場合、ユーザー A の友人が誰であるかを知る必要があるだけで、その逆は必要ありません。

ユーザー レコードが更新されたときに友情が双方向になるようにする動作を作成できます。その方が効率的でしょう。

注:私のコード例は、現在使用しているCakePHP 1.3用ですが、2.x でも問題なく動作するはずです。

于 2012-12-24T18:41:26.827 に答える
0

あなたの問題は、関連付けを誤って宣言したことが原因だと思います。これを試して:

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

Cakephp HABTM ドキュメントによると、

HABTM データは完全なセットのように扱われます。新しいデータの関連付けが追加されるたびに、データベース内の関連付けられた行の完全なセットが削除され、再度作成されるため、保存するために常にデータ セット全体を渡す必要があります。

2.1から、

保存操作中に余分なデータが失われるのを回避するために、独自の設定を keepExisting に設定できます。すなわち、

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 に答える
0

hasAndBelongsToMany 関係で使用されるものと同じエイリアス/名前を持つモデルを作成しないでください。これは私に CakePHP の頭痛の種でしかありませんでした。

例えば;

HABTM「ユーザー」が記録する「会社」というモデルがあります。私のデータベースには「companyies_users」というテーブルがあります。

Company モデルでこのようなことをしたくなるかもしれません。

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

次に、関連付けに追加のデータを保存するため、「CompanyUser」モデルを作成します。

これをしないでください。理由はわかりませんが、Cake は、「CompanyUser」という名前のモデルをいつ自動作成するか、作成した PHP ファイルを実際にいつロードするかを予測できません。

HABTM を定義するモデルでは、既定の関連付けを使用し、テーブルから別の名前のモデルを作成し、それを使用してレコードを処理するのが最適です。これにより、CakePHP も自動生成されたモデルを使用し、正しく動作することが保証されます。

したがって、私の例では、「useTable」変数を「company_users」に設定する「Members」というモデルを作成します。

「Company」モデルを使用すると、CakePHP が HABTM を正しく処理することがわかりました。これらの接続レコードにアクセスする必要がある場合は、「Members」モデルを使用します。

"with" オプションを使用するリスクは、CakePHP がいつ失敗し、モードを自動生成するかわからないことです。その場合、コールバックや動作は発生しません。

編集:

質問にもっと直接的に答えるために。

HABTM がより多くのデフォルトを使用するように、User.php モデル ファイルを変更します。

 public $hasAndBelongsToMany = array('Friend');

結合テーブル用に UserFriend.php モデル ファイルが定義されていないことを確認してください。結合テーブルを変更する必要がある場合は、データベース内のそのテーブルを指す別のエイリアスを持つモデルを使用してください。

于 2012-12-20T21:17:27.117 に答える
0

結合テーブルが呼び出されfriends、 というモデルが使用されFriendます。そして、HABTM 関係宣言を見ると、friendsテーブルには というフィールドと というフィールドが含まれてuser_idいるようfriend_idです。

friend_idテーブルにフィールドを配置することは、テーブルにフィールドを配置friendsするようなものですが、おそらく実行しないでしょう。Cake は を別のモデルを指す外部キーとして認識しているため、Cake はそれを好まないと思います。user_idusersfriend_idFriend

とにかく、同じテーブル間で 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 )

于 2012-12-18T21:47:00.420 に答える