Sign in Join
Wiki copytemporary

MasterDetail/ja: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: MasterDetail/ja

OldNewLine
1+## 概要
2+
3+リレーショナル データベースでは、マスター/ディテールの概念は 1 対多または 1:N とも呼ばれる。これは、テーブル/データセット内の 1 つのレコードが、別のテーブル/データセット内の多数のレコードに関連付けられる可能性があることを意味する。これは、あるデータセットのデータを使用して別のデータセットのデータをフィルター処理するモデルである。データのフィルタリングに使用されるデータセットはマスターと呼ばれ、フィルタリングされたデータセットはディテールと呼ばれる。たとえば、国には多くの都市があります。 国を選択し、そのすべての都市を表示したい場合は、マスター/ディテールに適した仕事である。国テーブルをマスター、都市テーブルをディテールにすることができる。フィルタリングが機能するのは、ディテール表にマスター表の識別子 (通常はマスター表の主キー) が含まれているためである。 したがって、このキーはマスターテーブルとディテールテーブルの両方に存在する。 ディテール テーブルでは外部キーと呼ばれる。
4+
5+マスター/ディテール関係の典型的な例は次のとおりである:
6+
7+- 顧客と注文
8+- 注文した商品を含む注文
9+
10+以下の例では、customer テーブルと order テーブルを操作する。
11+
12+## SQLDB 実装
13+
14+詳細データセットの **datasource** プロパティを使用して、マスター データセットにリンクできる。
15+
16+以下のアプローチは、組み込みの [[SQLdb Package]] データベース層を使用する Lazarus と FPC コードの両方に適用される。 他のデータベース層 (Zeo など) にも適用される場合がある。 ドキュメントを確認されたい。
17+
18+EMPLOYEE データベースの例 ([[SQLdb Tutorial0/ja]] および他のチュートリアルで使用されているもの):
19+
20+- 整数の主キー CUST_NO とその他のフィールドを持つ CUSTOMER テーブル
21+- CUSTOMER テーブルの CUST_NO フィールドにリンクする外部キーである CUST_NO 整数フィールドを持つ SALES テーブル
22+
23+フォーム上で:
24+
25+- 1 つの接続、1 つのトランザクションを使用するが、2 つのクエリ、2 つのデータ ソースを使用する
26+- qryCustomers というマスター クエリは CUSTOMER テーブルから選択する
27+- SALES テーブルから選択する qrySales というディテールクエリ
28+
29+ディテールクエリqrySalesで:
30+
31+- 通常通り、データベースプロパティを設定する
32+- データベースプロパティをマスターデータソースを示すように設定する
33+- クエリ SQL では、WHERE クエリを使用して選択を制限する。 詳細フィールド名を使用し、マスター テーブル内のフィールドの名前を持つパラメーターに制限する。
34+
35+``` SQL
36+SELECT * from SALES WHERE SALES.CUST_NO=:CUST_NO
37+```
38+
39+この場合、たまたまマスター フィールド CUST_NO と同じフィールド名を持つ SALES.CUST_NO フィールドを使用するが、そうである必要はない。マスター データソースはマスター クエリ qryCustomers の現在のレコードを追跡するため、FPC はマスター/qryCustomers クエリの CUST_NO フィールドの現在の値への参照として CUST_NO パラメーターを確認できる。
40+
41+マスター クエリにリンク *すべきではない* 追加のパラメーターをクエリで使用する場合は、マスター データセットを開く前に、その `Bound` プロパティが true であることを確認すること。[[doc:fcl/db/tparam.bound.html|doc:fcl/db/tparam.bound.htmlを]]参照のこと。
42+
43+フィールドを検索できるように、ディテールクエリの前にマスター クエリが開いていることを確認すること。
44+
45+### 適切な外部キーを使用したディテールレコードの追加
46+
47+ディテールレコードはマスター レコードとともにスクロールしますが、追加のコードが必要である。
48+
49+新しいディテールレコードを追加するとき、SALES.CUST_NO フィールドは、値を入力しない限り NULL のままである。したがって、qrySales の AfterInsert イベント ハンドラーを設定する必要がある:
50+
51+``` pascal
52+procedure TForm1.qrySalesAfterInsert(DataSet: TDataSet);
53+begin
54+ DataSet.FieldByName('CUST_NO').AsInteger := qryCustomers.FieldByName('CUST_NO').AsInteger;
55+end;
56+```
57+
58+### マスターデータを使用してフィルタリングしないディテールパラメータの使用
59+
60+デフォルトでは、詳細データセット内のすべてのパラメーターの値はマスター データセットによって提供される。 詳細データセットに個別にフィルター処理する別のパラメーターがあるとする:
61+
62+Master Query: Same as above
63+
64+Detail query:
65+
66+``` SQL
67+SELECT * FROM SALES WHERE SALES.CUST_NO=:CUST_NO AND OVERDUE=:CREDITOVERDUE
68+```
69+
70+解決策は、次のいずれかの方法を使用して、SQLDB に CREDITOVERDUE パラメータを「バインド」するように指示することである:
71+
72+1. オブジェクトインスペクタでパラメータの値を設定する。
73+2. マスター データセットを開く前に、パラメーターを (値に) バインド済みとしてマークする: `qryDetail.Params.ParamByName('CREDITOVERDUE').Bound:=True;` [[doc:fcl/db/tparam.bound.html|Bound property documentation]]参照。
74+3. マスター データセットを開く前にパラメーター値を設定する:
75+
76+`qryDetail.Params.ParamByName('CREDITOVERDUE').AsBoolean:=true;`
77+
78+### ディテール ブックマーク
79+
80+注意: TBufDataset および bufdataset の派生 (SQLQuery など)、マスター データセットのアクティブ レコードが移動するたびに詳細データセットが再ロードされる; したがって、既存のディテール ブックマークは、たとえ有効であっても、移動後は同じディテール レコードを指さなくなる。
81+
82+------------------------------------------------------------------------
83+
84+## **国と都市の例**
85+
86+このチュートリアルは SQLite を使用して作成されたが、原則は他のデータベースでも同じである。
87+
88+もしSQLiteの管理プログラムを持っていない場合、SQLite Studio <http://sqlitestudio.pl> を推奨する。
89+
90+- 初めに新しく SQLite データベースを作り、database.db3として保存する。
91+
92+(別のデータベース システムを使用する場合は、慣れているようにテーブルを作成し、例に適切なコンポーネントを使用するだけだ)。
93+
94+**ここで、2つのテーブルを作る**
95+
96+「国」テーブル:
97+
98+``` SQL
99+COUNTRY_ID (Primary key, integer, autoincrement)
100+COUNTRY_NAME (VARCHAR(50), not null)
101+```
102+
103+**テーブルに2つの国を追加する:**
104+
105+- Sweden
106+- Norway
107+
108+Because COUNTRY_ID が自動的に加算されるので、それぞれの国は自動的にIDがふられる。
109+
110+**「都市」テーブルを作る:**
111+
112+``` SQL
113+CITY_ID (Primary key, integer, autoincrement)
114+CITY_NAME (VARCHAR(50), not null)
115+COUNTRY_ID (integer, not null) (foreign key)
116+```
117+
118+**3つの都市をこのテーブルに追加する:**
119+
120+- Stockholm COUNTRY_ID 1
121+- Gothenburg COUNTRY_ID 1
122+- Oslo COUNTRY_ID 2
123+
124+空のテーブルに最初にスウェーデンが追加されたため、スウェーデンは COUNTRY_ID 1 を持ち、ノルウェーは COUNTRY_ID 2 を持つ。追加する都市ごとに、COUNTRY_ID を指定する必要がある。COUNTRY_ID によってテーブルがリンクされ、マスター/詳細の概念が可能になるためである。
125+
126+- Lazarus で新しいプロジェクトを作成し、MasterDetail として保存する。
127+- TSQLite3Connection をフォームに配置する(SQLdb tab)。
128+- TSQLite3Connection の DatabaseName プロパティに、作成したばかりの SQLite データベース ファイルのフル パスとファイル名を入力する。
129+- TSQLTransaction をフォームに配置する(SQLdb tab)。
130+- そのデータベース プロパティを: SQLite3Connection1へ。
131+- TSQLite3Connectionに戻り、TransactionプロパティをSQLTransaction1に設定する。
132+- TSQLite3Connection.Connected を true にする。
133+
134+**これでデータベースに接続できるようになり、次のステップに進むことができます。**
135+
136+- TSQLQueryをフォームに配置(SQLdb tab)。
137+- そのデータベースプロパティを: SQLite3Connection1にする
138+- Transaction プロパティを: SQLTransaction1にする。
139+- SQLステートメントに、以下を入力する:
140+
141+``` SQL
142+select * from countries
143+```
144+
145+- TDataSourceをフォームに配置(Data Access tab)。
146+- このデータセットを: SQLQuery1にする。
147+
148+- TDBGridをフォームに配置(Data Controls tab)。
149+- そのDataSourceプロパティを: DataSource1へ設定。
150+
151+- SQLQuery1 に戻り、Active を trueにする。
152+
153+**国テーブル (マスター) の内容が DBGrid1 に表示されるようになる。**
154+
155+- 次に都市テーブルに進みます(ディテール)
156+- 2つ目のTSQLQueryをフォームに配置(SQLdb tab)。
157+- そのデータベースプロパティを: SQLite3Connection1へ設定する。
158+- そのTransaction プロパティを: SQLTransaction1へ設定する。
159+- SQL ステートメントに、以下を入力する:
160+
161+``` pascal
162+select *
163+from cities
164+where cities.COUNTRY_ID = :COUNTRY_ID
165+```
166+
167+
168+COUNTRY_ID のコロン記号は、これが変数パラメーターであり、値が他の場所から取得されることを意味する。それはマスター データソースから値を取得する。したがって、この例では、:COUNTRY_ID 値はマスター データソースである DataSource1 によって提供される(パラメータ名は任意ではない。マスターテーブル内の関連するフィールド名である)。
169+
170+- そのDatasourceプロパティをDatasource1
171+
172+これではまだ都市を追加できない、これをする:
173+
174+- 上記の \#正しい外部キーを使用した詳細レコードの追加 にある情報を使用のこと。
175+
176+**ディテールビューを続行する:**
177+
178+- 2つ目のTDataSourceをフォームに配置。
179+- そのDataSetプロパティをQuery2 (ディテール クエリ)にする。
180+- 2つ目のDBGridをフォームに配置(ディテール グリッド)にする。
181+- そのDataSourceを DataSource2 (ディテール ソース)にする。
182+
183+**次に、グリッドにデータを流し込む。 これらをすべてアクティブ/接続済みに設定する:**
184+
185+- DBConnection
186+- Transaction
187+- Query1
188+- Query2
189+
190+これで、DBGrid2にディテールデータがあるはずだ。
191+
192+覚えておくべきことは、(上記のように) 詳細クエリのデータソースをマスター データソースに設定する必要があるということである (この例では DataSource1)。
193+
194+**それでも理解できなかった場合は、次の連結スキームを見ること:**
195+
196+Master Query.DataSource := None
197+
198+Master DataSource.Dataset := Master Query
199+
200+Master DBGrid.DataSource := Master DataSource
201+
202+Detail Query.DataSource := Master DataSource
203+
204+Detail DataSource.Dataset := Detail Query
205+
206+Detail DBGrid.DataSource := Detail DataSource
207+
208+## マスターレコードが削除された場合は、すべての詳細レコードを削除する
209+
210+これは、カスケード削除を使用すると簡単に実行できる。 繰り返すが、これは SQLite 用だが、他のシステムでも同様に動作する。
211+
212+- SQLite の外部キーはデフォルトでオフになっているため、まず SQLite の外部キーをオンにする。 これを行うには、TSQLite3Connection の Params プロパティに FOREIGN_KEYS=ON を追加する。
213+
214+- 次に、外部キー (country_id) がマスター テーブルを参照するように詳細テーブルが作成されていることを確認する。この場合、それは都市テーブルである:
215+
216+``` pascal
217+ try
218+ { マスターテーブル }
219+ Conn.ExecuteDirect('CREATE TABLE IF NOT EXISTS countries (' +
220+ ' country_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, ' +
221+ ' country_name VARCHAR(30) ' +
222+ ')');
223+ { ディテールテーブル }
224+ Conn.ExecuteDirect('CREATE TABLE IF NOT EXISTS cities (' +
225+ ' city_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, ' +
226+ ' city_name VARCHAR(30), ' +
227+ ' country_id INTEGER REFERENCES countries ON DELETE CASCADE' +
228+ ')');
229+ { サンプルデータ }
230+ Conn.ExecuteDirect('INSERT INTO countries(country_name) VALUES(''Sweden'')');
231+ Conn.ExecuteDirect('INSERT INTO cities(city_name, country_id) VALUES(''Stockholm'', 1)');
232+ Conn.ExecuteDirect('INSERT INTO cities(city_name, country_id) VALUES(''Malmo'', 1)');
233+
234+ Conn.ExecuteDirect('INSERT INTO countries(country_name) VALUES(''Norway'')');
235+ Conn.ExecuteDirect('INSERT INTO cities(city_name, country_id) VALUES(''Oslo'', 2)');
236+ Conn.ExecuteDirect('INSERT INTO cities(city_name, country_id) VALUES(''Bergen'', 2)');
237+
238+ Conn.Transaction.Commit;
239+ Conn.Close;
240+ except
241+ on E:Exception do
242+ begin
243+ TX.Rollback;
244+ ShowMessage( E.Message );
245+ end;
246+ end;
247+```
248+
249+以上である。 今後は、マスター レコードが削除されるたびに、すべての詳細レコードが自動的に削除される。
250+
251+注意: この方法で外部キーを有効にしようとしないこと:
252+
253+``` pascal
254+Conn.ExecuteDirect('PRAGMA foreign_keys = ON');
255+```
256+
257+TSQLite3Connection は、ExecuteDirect の場合でも、最初のクエリがデータベースに送信される前にトランザクションを開始する。 複数ステートメントのトランザクションの途中では (SQLite が自動コミット モードではない場合)、外部キー制約を有効または無効にすることはできない。 そうしようとしてもエラーは返されない。 それは単に効果がない。 出典: Ludob/SQLite ドキュメント。
258+
259+## さらにもう1つの例
260+
261+このフォーラムのトピックには、ソース コードを含む完全な実行例がある。
262+
263+新しい行を追加して DBGrid に保存する方法
264+
265+<http://forum.lazarus.freepascal.org/index.php/topic,42088.msg293305.html#msg293305>
266+
267+## 以下も参照のこと
268+
269+- <http://www.freepascal.org/docs-html/fcl/sqldb/usingparams.html> Documentation on using parameters, including implementation for master/detail
270+- <http://docwiki.embarcadero.com/RADStudio/XE3/en/Establishing_Master-detail_Relationships_Using_Parameters> The documentation for the equivalent Delphi feature
271+- <http://forum.codecall.net/topic/62683-master-detail-datasets/>
272+- [[Lazarus Tdbf Tutorial|Lazarus Tdbf Tutorial#Master table relations]] Example of using master/detail with the TDBF components
273+- [[SQLdb Tutorial0]] - Set up instructions for sample data for the subsequent database tutorials. Has master/detail tables
274+
275+---
276+*From the Free Pascal wiki, page "MasterDetail/ja", as it stood on 2024-03-31 after a change by Ariben, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
277+Category: Databases
278+Category: FPC
279+Category: Lazarus
280+Category: Tutorials

Back to history