Skip to content

コメントだけを追加・編集・削除する ​

第1版作成 最終更新 (日本時間)
確認バージョン1.5.8.1

本体の標準機能ではありません

このページは本体を改修する場合の設計メモです。1.5.8.1 では、コメントの追加・編集・削除はどれもレコード全体の更新として処理され、コメントだけを操作する API やサーバースクリプトのメソッドはありません。

前提にした現行の実装(1.5.8.1) ​

ソースへのリンクは Implem/Implem.Pleasanter の 1.5.8.1(コミット fdcbb3f8)固定です。

データの持ち方 ​

コメントは Issues・Results・Wikis の Comments 列に JSON 配列で入っています。1 件は CommentId・CreatedTime・UpdatedTime・Creator・Updator・Body を持ちます(Comment.cs#L12-L23)。新しいコメントは配列の先頭に入り、CommentId はそのレコード内の最大値 + 1 です(Comments.cs#L190-L208)。

json
[
    { "CommentId": 2, "CreatedTime": "2026-03-01T10:00:00", "Creator": 1, "Body": "新しいコメント" },
    { "CommentId": 1, "CreatedTime": "2026-02-28T09:00:00", "UpdatedTime": "2026-03-01T11:00:00", "Creator": 1, "Updator": 2, "Body": "編集したコメント" }
]

操作ごとの経路 ​

操作画面APIサーバースクリプト
追加更新ボタンでフォーム全体を送り、Comments の値を PrependUpdate(または Create)の Comments に本文を渡すと 1 件追加("[]" は無視。Comments.cs#L281-L293)model.Comments = "本文" で 1 件追加(ServerScriptUtilities.cs#L950)
編集フォームの Comment{番号} を更新と一緒に送る(ResultModel.cs#L2656-L2663)なしなし
削除専用アクション DeleteComment だが、中身はフォームを読んでレコードを更新する(ResultModel.cs#L2622-L2629)なしなし
取得レコードの一部として表示Get のレスポンスにレコードの一部として含まれるmodel.Comments

画面で編集できるのは自分が書いたコメントだけです(Creator == context.UserId。Comment.cs#L104-L107)。

サーバースクリプトで items.Update(id, model) に apiModel を渡すときは、Comments を null にしてから JSON にするため、取得したモデルを渡しても既存のコメントが二重に追加されることはありません(ServerScriptModelApiModel.cs#L435-L479)。

困ること ​

コメントの操作がレコードの更新と同じ処理を通るため、次のことが起こります。

  • レコードの UpdatedTime が変わり、他のユーザーの編集と更新日時の競合チェックでぶつかる
  • 「自動バージョンアップ」の設定や更新者・更新日によって、コメントだけの操作でも変更履歴が作られる
  • 更新前後のサーバースクリプト、通知の変更監視、入力検証がすべて動く
  • 画面ではフォーム全体を送るので、保存していない他の項目の変更も一緒に反映される
  • API・サーバースクリプトからは既存コメントの編集・削除ができない

設計案 ​

コメント専用の入口を足し、Comments 列だけを更新します。

図を読み込み中…

層追加するもの
DB 更新各モデル(IssueModel・ResultModel・WikiModel)に、Comments 列だけを更新する SQL を作るメソッド(履歴を作らない、UpdatedTime を変えない)
Web API/api/items/{id}/AddComment(Body)、UpdateComment(CommentId、Body)、DeleteComment(CommentId)、GetComments
画面コメント欄の送信を専用アクションにし、コメントの値だけを送る
サーバースクリプトitems.AddComment(id, body)、items.UpdateComment(id, commentId, body)、items.DeleteComment(id, commentId)、items.GetComments(id)
スクリプト$p.apiAddComment などのラッパー($p.apiExec で上の API を呼ぶ)
json
{
    "ApiVersion": 1.1,
    "ApiKey": "your-api-key",
    "CommentId": 3,
    "Body": "編集後の本文"
}

権限 ​

操作条件
追加レコードの更新権限
編集レコードの更新権限、かつ自分が書いたコメント(画面と同じ)
削除レコードの更新権限、かつ自分が書いたコメント(管理者の扱いは要検討)
取得レコードの読み取り権限

通知・履歴・ログ ​

  • 通知は、変更監視の対象に「コメント」が入っているときだけ送る
  • 変更履歴は作らない。コメントの変化は次にレコードを更新したときの履歴に含まれる
  • 操作は SysLogs に記録する(アクション名 addcomment など)

同時書き込みの問題 ​

コメントは 1 列の JSON 配列なので、「読んで、配列を変えて、書き戻す」処理になります。2 人がほぼ同時にコメントを追加すると、後から書いた方が先の追加を含まない配列で上書きし、先のコメントが消えます。UpdatedTime による競合チェックをやめると、この問題は画面の更新競合としても検出されなくなります。

図を読み込み中…

対策は 2 つあります。

方法内容規模
読み直してマージ同じトランザクションの中で Comments 列を行ロック付きで読み直し、その時点の配列に追加・変更を適用して書く。CommentId もこのとき採番する小〜中
専用テーブルに分けるComments テーブル(CommentId を自動採番、ReferenceId・ReferenceType・Creator・Body・日時)に 1 行ずつ持つ大(既存データの移行、表示・エクスポート・検索の改修が要る)

まずは JSON 配列のまま「読み直してマージ」で作り、ページングや大量コメントの性能が問題になったら専用テーブルを検討する、という順が現実的です。

改修時の注意 ​

モデル・ユーティリティ・コントローラの多くは CodeDefiner のテンプレートから生成されるコードです。追加するメソッドは、生成し直しで消えない場所(テンプレート側か、生成対象外のファイル)に置く必要があります(CodeDefiner)。

関連ページ ​

変更履歴

第1版サイト設定の変更履歴・拡張 SQL の外部 DB 接続・サイト名の解決・API ラッパー・ApiVersion の解説と、関連する改修・設計メモを追加