mcpField
O
objectstack-data

objectstack-data

github.com/objectstack-aiデータ・データベース76222 回インストール今日更新
リポジトリ

objectstack-data について

objectstack-dataは、ObjectStackのデータモデル作成者向けのプロトコルリファレンススキルです。オブジェクト、フィールド、関係、アクセス制御、ライフサイクル、データソースに加え、条件付きフィールド規則とスキーマ変更の制約を扱います。

主な機能

  1. 01オブジェクトとフィールド定義を参照
  2. 02関係・インデックス・検証を解説
  3. 03アクセス制御とデータライフサイクルを記載
  4. 04データソースとフェデレーション設定を説明
  5. 05条件規則とスキーマ変更を解説

活用シーン

  1. 01ObjectStackのオブジェクトとフィールドを設計
  2. 02データアクセスと保持ポリシーを設定
  3. 03フィールドの条件付き表示や必須条件を定義

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/objectstack-ai/objectstack --skill objectstack-data

インストール後、Claude Code で/objectstack-dataを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

evals/
hooks-security-seeds-datasources.json
README.md
objects-fields-relationships.json
references/
seeds.md
_index.md
lint-rules.md
examples-objects.md
data-hooks.md
rules/
datasources.md
field-types.md
naming.md
indexing.md
validation.md
security.md
lifecycle.md
relationships.md

詳細

データモデリング — ObjectStack Data Protocol

スキルの範囲

ニーズ代わりに使用
レコードをクエリ、フィルタリング、または集計するobjectstack-query
REST API エンドポイントまたは認証を定義するobjectstack-api
ビュー、ダッシュボード、またはアプリを構築するobjectstack-ui
プラグインを作成する、またはサービスを登録するobjectstack-platform

クイックリファレンス — 詳細ルール

誤った例と正しい例を含む包括的なドキュメントについては、以下を参照してください。

  • 命名規則 — snake_case のルール、オプション値、設定プロパティ
  • フィールドタイプ — 49 種類すべてのフィールドタイプと設定
  • リレーションシップ — lookup と master_detail の使い分け、中間テーブルのパターン、削除時の動作
  • 検証ルール — すべての検証タイプ、スクリプトの反転、重大度レベル
  • インデックス戦略 — btree/gin/gist/fulltext、複合インデックス、部分インデックス
  • データライフサイクルと保持 — lifecycle クラス(record/audit/telemetry/transient/event)、保持/TTL/ローテーション/アーカイブポリシー。❗ 追記専用オブジェクトではいずれかの指定が必須です(以下のライフサイクル フック とは別です)
  • ライフサイクルフック — 8 つのライフサイクルイベント、handler とサンドボックス化された body(ctx と capability の契約)、登録、標準パターン
  • データソースとフェデレーション — defineDatasource、外部/フェデレーションオブジェクト(remoteName/columnMap)、自動接続の制御、認証情報。❌ 外部オブジェクトでは field.columnName を使用しないでください
  • セキュリティとアクセス制御 — 権限セット、割り当て行、RLS ポリシー、secret / requiredPermissions、tenancy、プラットフォーム全体のセキュリティ態勢

コアコンセプト

オブジェクト定義

オブジェクトは、ObjectStack の基本的なデータエンティティです。データベーステーブルに対応し、CRUD API を自動的に公開します。

必須プロパティ:

プロパティ型規約説明
namestringsnake_case不変の機械識別子(/^[a-z_][a-z0-9_]*$/)
fieldsmapキーは snake_caseフィールド定義
sharingModelenum以下の4つのいずれか組織全体のデフォルトレコード可視性(OWD)。Zod では任意項目ですが、sharingModel を明示的に設定せずに公開しようとすると、422 の lint エンベロープ security-owd-unset により拒否されます。未設定は意思決定ではありません(メンテナーの判断、2026-08-13)。すべてのオブジェクトで設定してください

sharingModel — 正規の4つの値(ADR-0090 D4、レガシーエイリアスは削除済み)。省略されたカスタムオブジェクトは実行時に private として解決されますが、その前に公開時のチェックで拒否されます。

値読み取り/書き込みできるユーザー
private所有者のみ(共有ルール、RLS、または readScope/writeScope で範囲を拡大)
public_readすべてのユーザーが読み取り可能。書き込みは所有者のみ
public_read_writeすべてのユーザーが読み取りと書き込み可能
controlled_by_parentマスターレコードから継承(master_detail の子)

重要な任意プロパティ:

プロパティデフォルト説明
labelname から自動生成人が読める単数形のラベル
pluralLabel—複数形(例:「Accounts」)。リファレンスアプリの31個すべてのオブジェクトに設定されています。label と合わせて設定してください
icon—ナビゲーション、リストヘッダー、ルックアップピッカー用のアイコン名。リファレンスアプリの31個すべてのオブジェクトに設定されています
highlightFields派生レコードのコンパクトな表示に使用する、順序付きのフィールドキーです。親レコードの詳細ページで関連リストに表示される列、およびルックアップピッカーに表示される項目を指定します。子オブジェクトに宣言してください(リレーションシップを参照)
namespace—スキーマキーではありません。ObjectSchema.create() は不明なキーを拒否するため、設定するとビルドエラーになります。代わりに、接頭辞を name に直接含めてください(例:name: 'crm_account')
datasource'default'仮想化データの対象データソース ID
nameField派生(例:'name'/'title')レコードタイトルの正規フィールド。レコードの表示名として使用される、保存済みフィールドです。単一のテキスト/メールフィールドを使用するか、複合タイトルの場合は数式フィールド(returnType: 'text')を使用してください
displayNameField—nameField の非推奨エイリアス(フォールバックとして引き続き使用されます)
titleFormat—非推奨ですが削除されていません(ADR-0079)。レンダリング専用のため、サーバーから返したり、クエリしたりすることはできません。nameField を使用してください(こちらが優先されます)。複合タイトルの場合は、returnType: 'text' の数式フィールドを nameField に指定してください
enable—機能フラグ(trackHistory、searchable、apiEnabled など)
fieldGroups—フォーム/詳細ページ用の、論理フィールドグループの順序付きリスト(フィールドグループを参照)
lifecyclerecord のセマンティクス(永続)データ保持/ローテーション/アーカイブの契約。追記専用で書き込み頻度の高いオブジェクトでは必須です。telemetry/transient/event/audit クラスには上限を定めるポリシーを宣言する必要があり、宣言しないと解析に失敗します(データライフサイクルと保持を参照)
オブジェクトの機能(enable)

オブジェクトごとにシステムの動作を切り替えます。

フラグデフォルト目的
trackHistoryfalseフィールド単位の監査証跡
searchabletrueグローバル検索用にレコードをインデックス化
apiEnabledtrue自動 REST + MCP API 経由で公開
apiMethodsall6 つのプリミティブ(get、list、create、update、delete、bulk)の許可リスト。派生動詞(search/export/upsert/…)は自動的に適用されます
filesfalse添付ファイルとドキュメントの管理
feedstrueソーシャルフィード、コメント、メンション — オプトアウト:明示的に false を指定するとフィード UI が非表示になり、新しいコメントが拒否されます
activitiestrueアクティビティのタイムライン(CRUD をミラーする sys_activity) — オプトアウト:明示的に false を指定するとミラーリングが停止し、タイムラインが非表示になります
clonetrueレコードのディープクローン

検索フィールド(searchableFields)

オブジェクトの searchableFields は、$search が検索する正規のフィールド集合です(ADR-0061)。 未設定の場合、検索フィールドは nameField とオブジェクトの短文テキスト列および列挙型列(text / email / phone / url / autonumber / textarea / markdown / select / status)に自動設定されます。明示的に固定するには宣言してください。ビューで範囲を狭めることはできますが、広げることはできません。

⛔ 関連レコードのタイトルで検索する — 値を必ずミラーリングする

$search はクエリ対象オブジェクト自身の列を検索します。ドット付きパスは検索対象になりません。fields / sort / filters とは異なり、検索軸ではパスをたどって解決しません。また、searchableFields(または $searchFields のオーバーライド)に指定した project_id.name は、黙って除外されるのではなく拒否されます。

これは唯一の指針です。毎回このとおりにしてください。 関連レコードのタイトルで検索するには、そのタイトルをこのオブジェクト上の保存フィールドにコピーし、そのフィールドを検索可能として宣言します。プロジェクト名で検索するタスクリストの場合:

// `project_name` is a stored, denormalized mirror of the parent's title.
{
  name: 'task',
  enable: { searchable: true },
  fields: {
    name:         { type: 'text', required: true },
    project_id:   { type: 'lookup', reference: 'project' },
    project_name: { type: 'text', label: 'Project Name' },   // ← the mirror
  },
  searchableFields: ['name', 'project_name'],
}

?search=apollo は name $contains 'apollo' OR project_name $contains 'apollo' に展開されます。すべてのドライバーで、パスをたどることなく、単一テーブルを 1 回スキャンします。(オブジェクトで searchableFields が宣言されていない場合、text のミラーフィールドも自動設定されるフィールド集合に含まれます。)

❌ formula フィールドには絶対にミラーリングしないでください。 formula フィールドは仮想フィールドです。ドライバーはその列を実体化しないため、これに対する $contains 述語には検索対象がありません(SQL ドライバーは、存在しない列を対象とした WHERE を生成してしまいます)。また、CEL が読み取れるのはこのレコード自身のフィールド(record.<field>)だけなので、formula ではそもそも関連タイトルを取得できません。この誤りは黙って処理されるのではなく拒否されます。searchableFields 内の formula(オブジェクト自身のフィールド集合を含む)は os validate エラー(searchable-field-unsearchable)となり、これを指定したリクエストは 400 INVALID_FIELD になります。以前は両方ともクリアされ、その後は検索に一致しませんでした。

ミラーの保守はトレードオフです。ミラーは非正規化データであり、値を書き込む処理が実行された時点でのみ最新になります。次の両方の書き込み経路をカバーしてください。

タイミングミラーを保守する処理
タスクが作成されたとき、または別のプロジェクトに付け替えられたときtask の beforeInsert / beforeUpdate フック — 入力された project_id に対応する親の name を読み取り、project_name に設定します
プロジェクト名が変更されたときproject の afterUpdate フック — そのプロジェクトのタスクの project_name を再設定します

フックを経由しない経路(一括インポート、直接 SQL)で書き込まれた行には、1 回限りのバックフィルが必要です。ライフサイクルフックを参照してください。

どちらの表記も明示的に拒否されます。os validate は searchable-field-unknown を報告し、ドット付きパスを指定したリクエストは 400 INVALID_FIELD になります。それぞれのメッセージには、対応方法が記載されています。

オブジェクト間の検索パスは、今後対応する予定がないのではなく、設計上拒否されています。このためのプロジェクトごとの慣習を新たに作らないでください。ミラーフィールドが答えです。


→ references/examples-objects.md § Field Groups (MVP) にそのまま移動しました。


条件付きフィールドルール

データモデルに属し、フィールドの編集箇所すべてで適用するルールは、フィールド定義に設定します。対象には、デフォルトのフォーム、Studio で作成したフォーム、インラインのマスターディテールグリッド、公開フォーム、API 経由の書き込みが含まれます。

import { P } from '@objectstack/spec';
import { ObjectSchema, Field } from '@objectstack/spec/data';

export const Invoice = ObjectSchema.create({
  name: 'invoice',
  sharingModel: 'private',
  fields: {
    status: Field.select({
      options: [
        { label: 'Draft', value: 'draft' },
        { label: 'Sent', value: 'sent' },
        { label: 'Paid', value: 'paid' },
        { label: 'Void', value: 'void' },
      ],
    }),
    paid_at: Field.datetime({
      visibleWhen: P`record.status == 'paid'`,
      requiredWhen: P`record.status == 'paid'`,
    }),
    locked_total: Field.currency({
      readonlyWhen: P`record.status == 'paid'`,
    }),
  },
});
  • ObjectUI フォームで関連性のないフィールドを非表示にするには、visibleWhen を使用します。
  • 状態によってロックされるフィールドには readonlyWhen を使用します。述語が TRUE の場合、ObjectQL の書き込み処理は受信した変更を無視します。
  • readonly: true が適用されるのはエンドユーザー向けの画面であり、信頼されたシステムライターではありません。 非システムの書き込み(REST/UI、およびデフォルトの runAs:'user' フロー)では、フィールドは非システムの書き込みから除外されます。書き込みは成功と報告されますが、値は保存されません。システムコンテキストでの書き込み(runAs:'system' フロー、システムフック、シード、インポート、マイグレーション)は対象外となり、書き込みが行われます。したがって、「ユーザーは編集できないが、自動化によって維持する」というパターンは、フィールドに readonly を宣言し、維持するフローを runAs:'system' で実行することで表現します(objectstack-automation を参照)。readonly を削除して実現するものではありません。runAs:'user' の update_record ノードから readonly フィールドに書き込むと、ビルド時のエラーになります(os validate/os build)。
  • 条件付きで必須にするには requiredWhen を使用します。ObjectQL バリデーターは送信時にこれを適用します。conditionalRequired エイリアスはプロトコル 17 で削除されました。出力すると解析エラーになります。
  • 意図に応じて選択してください — 不変条件か、遷移のゲートか。 すべての保存済みレコードに当てはまる事実は不変条件であり、validations[] の script ルールを使用します。これに違反する行は、修正されるまで編集できません。「レコードが paid に達したら必須」のような遷移条件には requiredWhen/フィールドの制約を使用します。これは保存済みの行ではなく、書き込みを判定します。「X のとき必須」は不変条件のように見えますが、そうではありません。不変条件をゲートとして記述しても、それ自体が適用されることはありません。
  • インラインの master_detail グリッドでは、述語は子行の record を基準に行ごとに評価されるため、明細行のルールは子フィールドに設定してください。
  • 複雑な述語には objectstack-formula を読み込み、P\...`を使って CEL を出力してください。Salesforce 形式のAND、IN (...)、{field}` 構文は使用しないでください。

→ references/examples-objects.md § クイックスタートテンプレートにそのまま移動しました。


既存データベースのスキーマ進化

メタデータから DB への同期は追加のみです。起動時に新しいテーブルやカラムは作成されますが、既存のカラムが変更または削除されることはありません。すでにデータがあるオブジェクトに対する追加以外の変更は、物理スキーマとの不一致を暗黙に生じさせます。また、書き込み時にはデータベースのカラム定義が優先されます。

変更再起動時の既存 DB
オブジェクト/フィールド/インデックスの追加✅ 自動で適用(追加のみ)
storage: { notNull: true } の削除(NOT NULL の緩和)⚠️ 自動適用されません — 不一致は category: 'needs_confirm'(relax_not_null)となるため、os migrate apply で確定します。required のみを緩和してもカラムは変わりません
unique のスコープをグローバルからテナント単位に変更開発環境では自動修復。それ以外では os migrate apply(replace_unique_index)
型/長さの変更、フィールドの削除、名前の変更os migrate apply(削除/制約強化には --allow-destructive)
宣言済みインデックスの削除、またはそのカラムの変更os migrate apply(削除時、または UNIQUE として再構築する場合は --allow-destructive)

required は NOT NULL の設定ではありません(ADR-0113)。 required は書き込み時の契約です。値を省略した挿入をエンジンが拒否しますが、カラムについては何も規定しません。物理的な制約は別途明示的にオプトインする storage: { notNull: true } であり、不一致検出ではこれを比較します。そのため、デプロイ済みオブジェクトの required を厳しくしても安全です(既存の null 行は引き続き読み取れます)。一方、null 行がある状態で storage.notNull を宣言するのは、破壊的なマイグレーションです。requiredWhen とこの 2 つを併用することはできません。条件付きの契約を、無条件のカラム制約にはできないためです。

よくある兆候:/meta ではフィールドが省略可能(required も storage.notNull もない)と報告される一方、値を省略した書き込みが、明確なバリデーションエラー 400 ではなく生のドライバーエラーで失敗します。これはバリデーターの不具合ではなく、古い NOT NULL カラムです。os migrate plan を実行してプレビューし、os migrate apply で調整するか、storage: { notNull: true } を宣言してそのカラムを正式な定義としてください。CLI の詳細については、objectstack-platformを参照してください。


よく使うパターン

命名規則の概要
コンテキスト規則例
オブジェクトの namesnake_caseproject_task
フィールドキーsnake_casefirst_name、due_date
スキーマプロパティcamelCasemaxLength、lookupFilters
オプションの value小文字in_progress

誤りと正しい例については、rules/naming.mdを参照してください。

フィールド型の選択

49 種類の型を利用できます。主なカテゴリは次のとおりです。

  • テキスト: text、textarea、email、url、phone、password、markdown、html、richtext — ⚠️ 汎用オブジェクトの password は、保存時に平文です(読み取り時はマスクされますが、ハッシュ化はされません)。認証情報には secret を推奨します
  • シークレット: secret — 登録済みの ICryptoProvider を介して、認証情報(DB パスワード、API キー、トークン)を可逆的に保存時暗号化します。読み取り時はマスクされ、フェイルクローズで動作します(ADR-0100)。認証情報に推奨される型です
  • 数値: number、currency、percent
  • 日付/時刻: date、datetime、time
  • ロジック: boolean、toggle
  • 選択: select、multiselect、radio、checkboxes
  • リレーショナル: lookup、master_detail、tree、user — user は人物選択フィールドです(sys_user に特化した lookup で、lookup と同じ形式で保存されます)
  • メディア: image、file、avatar、video、audio
  • 計算: formula、summary、autonumber — formula フィールドでは expression に CEL 式を指定します(@objectstack/spec の F\...`` を使用)。objectstack-formulaスキルを参照してください
  • 埋め込み: composite、repeater、record — 親行に保存される埋め込み JSON サブオブジェクトです(個別のテーブル/FK はありません)
  • 拡張: location、address、code、json、color、rating、slider、signature、qrcode、progress、tags、vector

全リファレンスについては、rules/field-types.mdを参照してください。

関係パターン
パターン実装
1 対多(独立)子に lookup フィールド
1 対多(所有)子に master_detail フィールド
多対多(シンプル)複数値の lookup(multiple: true)— ID の 配列カラム
多対多(属性あり)2 つの lookup フィールドを持つ中間オブジェクト
階層型tree フィールド(自己参照)

詳しい例については、rules/relationships.md を参照してください。

multiple: true の lookup ≠ 中間オブジェクトです。 複数値の lookup ({ type: 'lookup', reference: 'x', multiple: true })は、レコード上に ID の 配列として保存され、読み取られます。フローの値では位置を指定して 要素を参照します({record.tags.0})。これは中間テーブルではありません。 中間オブジェクト(2 つの lookup)を使用するのは、関係そのものに 属性(role、added_at、…)が含まれる場合に限ります。

検証パターン

⚠️ スクリプト検証のロジックは逆です: 式が true の場合、検証は失敗します。

挿入時に、ペイロードから省略された任意フィールドは、検証述語内では null として読み取られます。そのため record.due_date == null は、 明示的な null と同様に、省略されたフィールドにも一致します。 (更新時は、以前のレコードから値が引き継がれます。)

検証タイプの完全な一覧(ValidationRuleSchema の判別子):

  • script — 数式式(ロジックは逆)
  • state_machine — 有効な状態遷移
  • format — 正規表現または組み込み形式
  • cross_field — フィールド間の値を比較
  • json_schema — JSON フィールドを JSON Schema に照らして検証
  • conditional — 述語が成立する when の場合にのみ、ネストされたルールを適用

unique 検証タイプはありません(仕様から削除されました)。 複合条件を含む一意性は、一意インデックスで適用し、そのスコープを指定してください(ADR-0120): indexes: [{ fields: ['department', 'email'], unique: 'organization' }]。

すべてのタイプと例については、rules/validation.md を参照してください。

インデックスパターン

宣言で使用できる項目は fields / unique / name のみです。 unique のデフォルトは false です。該当する場合は省略してください。

indexes: [
  { fields: ['status', 'created_at'] },                // composite
  { fields: ['email'], unique: 'organization' },       // unique per organization
  { fields: ['hostname'], unique: 'global' },          // unique platform-wide
  { name: 'idx_acct_status', fields: ['status'] },     // custom name
]

type と partial はプロトコル 17 で廃止されました:どちらもドライバーで 読み取られたことがないため、記述した type はアクセス方式を選択せず、記述した partial は述語が破棄されて完全なインデックスが生成されていました。どちらも tsc エラーおよび解析エラーになりました。os migrate meta --from 16 で変更点を確認できます。 --write は証明可能な変更を適用します。それ以外は手動で対応してください。

一意インデックスではスコープを指定する必要があります — 'organization' (組織ごとに 1 件、NULL セーフ)または 'global'(インストール全体で 1 件)。 宣言されたインデックスで unique: true とだけ記述するのは、非推奨の 'global' の表記です。「組織ごと」と読めて実際の動作が逆になるため、os lint は警告し、プロトコル 18 では拒否されます。FIELD での unique: true は 'organization' を意味し、引き続き有効です。

複合インデックス、一意性のスコープ、データベースレイヤーで partial/gin/gist インデックスを作成する方法については、rules/indexing.md を参照してください。

→ そのまま references/examples-objects.md の § Lifecycle Hooks に移動しました(フックのリファレンス自体は references/data-hooks.md です)。



オブジェクト拡張モデル

所有していないオブジェクトにフィールド/検証/インデックスを追加するには、 defineObjectExtension({ extend, fields, priority }) を記述し、 defineStack({ objectExtensions: [...] }) に登録します。priority はマージ順序を設定します(デフォルト 200、範囲 0–999)。拡張で追加はできますが、削除はできません。⛔ オブジェクトレベルの ownership(レコード所有権の列挙型 'user' | 'business_unit' | 'org' | 'none')とは別のキーです。スキーマ: node_modules/@objectstack/spec/src/data/object.zod.ts(ObjectExtensionSchema)。


セキュリティとアクセス制御

オブジェクトごとのアクセス制御は、オブジェクトスキーマではなく権限セットで定義します。オブジェクトレベルのpermissionsキーは存在せず、hooksキーもありません。ObjectSchema.create()は、どちらも不明なキーとして拒否します。

ルールの全文は、**セキュリティとアクセス制御**を参照してください。

アクセス深度(scope-depth)— ERPの「自分のユニットを見る/自分のユニットとその下位を見る」軸

所有者スコープが設定された(private)オブジェクトでは、権限セット内のオブジェクトごとの権限付与にreadScope/writeScopeを指定すると、RLSポリシーを手作業で記述せずに、宣言的に所有者との一致範囲を広げられます(ADR-0057 D1):own(デフォルト)· own_and_reports · unit · unit_and_below · org。リクエスト時にowner_id IN (…)セットに解決され、RLSと同様にAND条件で挿入されます。⚠️ オープンコアの境界(ADR-0016):オープンソースで動作するのはownとorgのみです。階層を基準とする3つの値には有料の@objectstack/security-enterpriseプラグインが必要です。このプラグインがない場合はデフォルトでownに制限され、権限付与でrequires: ['hierarchy-security']を宣言していないとdefineStackはエラーになります。スキーマ:PermissionSetSchema.objects.*。


→ references/examples-objects.md § Metadata Protection(protection)にそのまま移動しました。


→ Seed Data & Fixtures(defineSeed())は、references/seeds.md(クイックスタート · Seedのフィールド · インポートモード · externalIdの選択 · リレーションシップ参照 · 動的な値(CEL) · シードのベストプラクティス)にそのまま移動しました。


→ Linting & Generation Qualityは、references/lint-rules.mdにそのまま移動しました。


作業を検証する

*.object.ts/*.seed.tsを新規作成または編集した後は、完了を報告する前に、作成時のゲートを実行してください。

os validate     # Zod schema + CEL predicates (record.<field> existence) + bindings
# or: os build  # the same gates, plus emits dist/

これにより、通常は実行時に何も通知されず失敗する問題を検出できます。たとえば、requiredWhen/readonlyWhen/visibleWhen、バリデーションルール、数式、行レベルのセキュリティ/共有の述語で、フィールド参照をそのまま記述した場合(record.doneではなくdone)、評価結果がnullになり、条件が発動しません。os lintは別の検査であり、このスキルの規約(リレーションシップ、マスター詳細、ロールアップ)に対するデータモデルの追加チェックも行います。これも実行してください。ただし、os validateの代わりにはなりません。(注意:ソースに変更を加えずにos buildを連続して2回実行した場合、出力はバイト単位で同一でなければなりません。前述の決定性ゲートを参照してください。)スキャフォールドされたプロジェクトでは、ゲートのコマンドはnpm run validateです。


リファレンス

Zodスキーマの一覧(各スキーマの説明付き)は、references/_index.mdを参照してください。ここからnode_modules/@objectstack/spec/src/内のファイルに移動できます。フィールドの正確な形状を確認するには、必ずソースをReadしてください。プロパティ名の記憶に頼らないでください。

コメント