データベースとロジッククラスの連携について
投稿者 るきお  (社会人)
投稿日時
2010/6/28 13:31:06
こんにちは。
>例えば、OleDbを使用しているとするならばOleDbCommandに対しパラメーターを
>追加しなけばなりません。
>その場合に、業務ロジック側から作成するのであればOleDbCommandのスコープは
>最大限に拡げねばならなくなります。
引数の受け渡しなどを使用すれば、必ずしもスコープを最大限にまでする必要はないと思います。
>かといってデータベースクラスにパラメータクエリ用のメソッド等を用意した場合
>データベースのフィールドを直に指定しなければなりません。
業務ロジッククラスでパラメータを指定するようにしてもデータベースのフィールドを直に指定することは避けられないですよね?
>何か良い方法やパターンはありますか?
要するに、データベースの物理的な構造に影響されないようにするにはどうしたらよいか
ということを考えられているのでしょうか?
まず、今回のようにUI層(フォームクラス)と、ロジック層(業務ロジッククラス)とデータアクセス層(データベースクラス)で役割分担させてシステムを構築する場合、
データベースの物理構造に影響される部分は極力データアクセス層に記述することになっています(一般的には)。
このようにしておいて、データベースの物理構造の変更はデータアクセス層で吸収してUIやロジックはそのまま使いまわすことができるようになるのが理想です(が、実際にはデータベースの構造を変化させるときにはそれなりの要求があるのでなかなかデータ層だけで綺麗にはできません)。
データ層のプログラムも自分でデータベースのテーブル名やフィールド名を書くのではなく、できるだけ柔軟性をもたせ、開発作業も楽をするというのがここ数年のトレンドです。
たとえば、やや古い技術ですが型付データセットを使えば、データ層のプログラマはテーブル名やフィールド名を直接書く必要はなくなります。最近の技術ではADO.NET EntityframeworkやLink to sqlなどがあります。
ここからは私の意見ですが、これらの技術をつかっても裏では(大量の?)コードが自動生成され、そこにはテーブル名やフィールド名が埋め込まれています。GUIやウィザードでメンテできるので自分で書くよりは楽という意見もありますが、いざというときのトラブルシューティングが困難ですし、ブラックボックスを抱え込んでしまっているようでちょっと気持ち悪いです。規模の大小もありますが普通のシステム構築であればリリース前にコーディングレベルのトラブルの10個や20個は普通におきますよね。(コードは見られますので別にブラックボックスではないのですが、チーム全員が理解することを要求できない状態と思います。)
まとめると、これらの技術を使った場合
メリット:データベースの構造に変更があった場合、プログラム側でビルドエラーを検知できるようになるので、修正すべき箇所がすぐわかる。
デメリット:技術をちゃんと理解していないと何をすればいいのかわからない。チューニングやトリッキーな技がかなり使用しにくくなり、いざというときの壁になるときがある。
では、どうすればいいのかと言うと、あくまで私の意見ですが、
スタンス1
テーブル名やフィールド名などの物理構造は「できるだけ」データアクセス層に持たせるが、あまりそのことにこだわりすぎない。→再利用性は当然低下しますが、実際のところこの手のクラスはほどんと再利用しない。データベースの変更の影響での修正箇所は多くなり、しかもビルド時に検出されにくくなってしまいますが、テストでカバー。(どうせ、ウィザードで修正してもテストはします。)
メリット:直感的な開発。ベタな構造だがその分理解されやすくメンテできるシステムになる。
デメリット:工数がやや多い。テストが重要。
スタンス2
ある程度のテーブルはエンティティのようなクラスを作っておいて、プログラムからは間接的にのみアクセスできるようにする。ただし、そのことにこだわりすぎず必要であればためわらずテーブル名やフィールド名を直接指定する。あとはスタンス1と同じ。
メリット:スタンス1よりメンテの工数が節約できる可能性がある。(ビルドエラーでの検出もより多く可能になる。)。中のコードも比較的ベタなつくりになるので理解されやすい。
デメリット:ウィザードやデザイナを使って完全にエンティティ化するよりも工数がかかる。
ちょっと長く書きすぎました。こんな方向性の話しでよかったでしょうか?
>例えば、OleDbを使用しているとするならばOleDbCommandに対しパラメーターを
>追加しなけばなりません。
>その場合に、業務ロジック側から作成するのであればOleDbCommandのスコープは
>最大限に拡げねばならなくなります。
引数の受け渡しなどを使用すれば、必ずしもスコープを最大限にまでする必要はないと思います。
>かといってデータベースクラスにパラメータクエリ用のメソッド等を用意した場合
>データベースのフィールドを直に指定しなければなりません。
業務ロジッククラスでパラメータを指定するようにしてもデータベースのフィールドを直に指定することは避けられないですよね?
>何か良い方法やパターンはありますか?
要するに、データベースの物理的な構造に影響されないようにするにはどうしたらよいか
ということを考えられているのでしょうか?
まず、今回のようにUI層(フォームクラス)と、ロジック層(業務ロジッククラス)とデータアクセス層(データベースクラス)で役割分担させてシステムを構築する場合、
データベースの物理構造に影響される部分は極力データアクセス層に記述することになっています(一般的には)。
このようにしておいて、データベースの物理構造の変更はデータアクセス層で吸収してUIやロジックはそのまま使いまわすことができるようになるのが理想です(が、実際にはデータベースの構造を変化させるときにはそれなりの要求があるのでなかなかデータ層だけで綺麗にはできません)。
データ層のプログラムも自分でデータベースのテーブル名やフィールド名を書くのではなく、できるだけ柔軟性をもたせ、開発作業も楽をするというのがここ数年のトレンドです。
たとえば、やや古い技術ですが型付データセットを使えば、データ層のプログラマはテーブル名やフィールド名を直接書く必要はなくなります。最近の技術ではADO.NET EntityframeworkやLink to sqlなどがあります。
ここからは私の意見ですが、これらの技術をつかっても裏では(大量の?)コードが自動生成され、そこにはテーブル名やフィールド名が埋め込まれています。GUIやウィザードでメンテできるので自分で書くよりは楽という意見もありますが、いざというときのトラブルシューティングが困難ですし、ブラックボックスを抱え込んでしまっているようでちょっと気持ち悪いです。規模の大小もありますが普通のシステム構築であればリリース前にコーディングレベルのトラブルの10個や20個は普通におきますよね。(コードは見られますので別にブラックボックスではないのですが、チーム全員が理解することを要求できない状態と思います。)
まとめると、これらの技術を使った場合
メリット:データベースの構造に変更があった場合、プログラム側でビルドエラーを検知できるようになるので、修正すべき箇所がすぐわかる。
デメリット:技術をちゃんと理解していないと何をすればいいのかわからない。チューニングやトリッキーな技がかなり使用しにくくなり、いざというときの壁になるときがある。
では、どうすればいいのかと言うと、あくまで私の意見ですが、
スタンス1
テーブル名やフィールド名などの物理構造は「できるだけ」データアクセス層に持たせるが、あまりそのことにこだわりすぎない。→再利用性は当然低下しますが、実際のところこの手のクラスはほどんと再利用しない。データベースの変更の影響での修正箇所は多くなり、しかもビルド時に検出されにくくなってしまいますが、テストでカバー。(どうせ、ウィザードで修正してもテストはします。)
メリット:直感的な開発。ベタな構造だがその分理解されやすくメンテできるシステムになる。
デメリット:工数がやや多い。テストが重要。
スタンス2
ある程度のテーブルはエンティティのようなクラスを作っておいて、プログラムからは間接的にのみアクセスできるようにする。ただし、そのことにこだわりすぎず必要であればためわらずテーブル名やフィールド名を直接指定する。あとはスタンス1と同じ。
メリット:スタンス1よりメンテの工数が節約できる可能性がある。(ビルドエラーでの検出もより多く可能になる。)。中のコードも比較的ベタなつくりになるので理解されやすい。
デメリット:ウィザードやデザイナを使って完全にエンティティ化するよりも工数がかかる。
ちょっと長く書きすぎました。こんな方向性の話しでよかったでしょうか?
投稿者 tecc  (社会人)
投稿日時
2010/6/29 08:55:33
文章を引用したかったのですがやたら引用符を使用するはめになってしまったので
冒頭のみ引用させて頂きました。
まず、拙い文章を汲み取っていただいてありがとうございます。
>まず、今回のようにUI層(フォームクラス)と
おっしゃっているようにデータベースの物理構造の変更はデータアクセス層で吸収し
UIやロジックはそのままなのが理想です。
で、さらにおっしゃられているデータベースの構造の変化時や僅かなテーブル構造の
変化が発生する等は普通にありえる話ですから全てが綺麗にとは言い切れません。
なのでできる限り又は他の人が読めるものは何か?と思った所
僕は[一般的]なという事を回りに聞ける環境ではなかった為このような質問に至りました。
一時期 O/Rマッピングについて調べた事があるのですがいかんせんすぐに実用化とは
いかない代物でSQLなどの所謂ブラックボックスの部分が発生するんですね。
使った事がないのでデメリットの実感もありませんが、使用するデータベースが
Oracleが多いのでチューニングが行い難くなると致命的かもしれません。
じっくりと検討と精査を行ってみます。
スタンス1について
現在はやはりこちらでやっています。今まで何回か迷った中で少しでも'纏め'様とした所
必然的にデータアクセス層になっていました。
スタンス2について
テーブルのエンティティクラス、クラス自体をテーブルそのものと見たてたクラスを
作成するという事ですか?
冒頭のみ引用させて頂きました。
まず、拙い文章を汲み取っていただいてありがとうございます。
>まず、今回のようにUI層(フォームクラス)と
おっしゃっているようにデータベースの物理構造の変更はデータアクセス層で吸収し
UIやロジックはそのままなのが理想です。
で、さらにおっしゃられているデータベースの構造の変化時や僅かなテーブル構造の
変化が発生する等は普通にありえる話ですから全てが綺麗にとは言い切れません。
なのでできる限り又は他の人が読めるものは何か?と思った所
僕は[一般的]なという事を回りに聞ける環境ではなかった為このような質問に至りました。
一時期 O/Rマッピングについて調べた事があるのですがいかんせんすぐに実用化とは
いかない代物でSQLなどの所謂ブラックボックスの部分が発生するんですね。
使った事がないのでデメリットの実感もありませんが、使用するデータベースが
Oracleが多いのでチューニングが行い難くなると致命的かもしれません。
じっくりと検討と精査を行ってみます。
スタンス1について
現在はやはりこちらでやっています。今まで何回か迷った中で少しでも'纏め'様とした所
必然的にデータアクセス層になっていました。
スタンス2について
テーブルのエンティティクラス、クラス自体をテーブルそのものと見たてたクラスを
作成するという事ですか?
投稿者 るしぇ  (社会人)
投稿日時
2010/7/5 14:37:05
ボクはテーブル名やフィールド名とかは、データ層ではなく、
ビジネスロジック層に分類しています。業務モデル化した
時点でこれらは決定され、データベースとはほぼ1:1対応、
後からフィールド名やテーブル名を変えることはまずありません。
変更はビジネスロジック層に依存していると思います。
そう考えると
>例えば、OleDbを使用しているとするならば
.NET Framework 上で三層アーキテクチャの話をするなら、
データベース層は本当に接続のみだから OleDb そのもので
いいのでは?汎用性あるでしょう?そのままで。
>その場合に、業務ロジック側から作成するのであればOleDbCommandの
>スコープは最大限に拡げねばならなくなります。
ない。既存のクラスで言うなら OleDb がフィールド名を参照できる
スコープで定義されないと動かないとか。。。これはない。
パラメータで受け渡せば済む事。
それに対して具体的なパラメータを設定するのは、一般に
ビジネスロジック部分で、汎用性とか言っても、マスタメンテと
実績入力なんて共通化する意味はないでしょう。むしろほぼ同じ
ロジックでも、発注と売上で税計算の適用が違うなど、敢えて
別にすべき場合さえ発生します。
業務モデルの構造次第なのだから、汎用性を求めること自体
少ないです。
>で、さらにおっしゃられているデータベースの構造の変化時や僅かなテーブル構造の
>変化が発生する等は普通にありえる話ですから全てが綺麗にとは言い切れません。
実際に経験の蓄積があるのだから、それを分析すべきでしょう。
僅かなといいつつ、フラグのフィールドなんかが追加になってたら、
それはもう業務ロジックが変わっているのでは?
データ層の修正のみに収まりそうな事例があったなら、もう少し
具体的なサンプルデータを出してもらえませんか。
三層構造が特に重要視されるWEB アプリでも、ビジネスロジック
層はアプリケーションサーバ上に置かれる事が多いと思います。
ここは特に重要で、WEB アプリの場合、データベースの構造及び
業務ロジックに関する情報はサーバ外に漏れないようにします。
アプリケーション層との完全な分離ですね。
セキュリティ面と、修正が発生した場合に、その範囲をサーバ内
に収める為です。
アプリケーション層とビジネスロジック層の分離で悩む事は多い
ですが、データ層は本当に既存クラスで収まると思ってました。
> エンティティクラス
必要だとしても、DataRow あたりで十分だと思うんですが。。。
> Oracleが多いのでチューニングが行い難くなると致命的かもしれません。
これも、よくある実行計画の分析なんかだと、SQL そのものが
がらりと変わる場合があると思います。下手にデータ層に
入れ込まないほうが良いんじゃないかなぁ。
クラス作るより先に、既存クラスをもっとよく見るべきかも。
ほぼそのまま利用すれば良いものも多いのでは?
究極の汎用的ってのは、自作クラス数0の事だと思います。
ビジネスロジック層に分類しています。業務モデル化した
時点でこれらは決定され、データベースとはほぼ1:1対応、
後からフィールド名やテーブル名を変えることはまずありません。
変更はビジネスロジック層に依存していると思います。
そう考えると
>例えば、OleDbを使用しているとするならば
.NET Framework 上で三層アーキテクチャの話をするなら、
データベース層は本当に接続のみだから OleDb そのもので
いいのでは?汎用性あるでしょう?そのままで。
>その場合に、業務ロジック側から作成するのであればOleDbCommandの
>スコープは最大限に拡げねばならなくなります。
ない。既存のクラスで言うなら OleDb がフィールド名を参照できる
スコープで定義されないと動かないとか。。。これはない。
パラメータで受け渡せば済む事。
それに対して具体的なパラメータを設定するのは、一般に
ビジネスロジック部分で、汎用性とか言っても、マスタメンテと
実績入力なんて共通化する意味はないでしょう。むしろほぼ同じ
ロジックでも、発注と売上で税計算の適用が違うなど、敢えて
別にすべき場合さえ発生します。
業務モデルの構造次第なのだから、汎用性を求めること自体
少ないです。
>で、さらにおっしゃられているデータベースの構造の変化時や僅かなテーブル構造の
>変化が発生する等は普通にありえる話ですから全てが綺麗にとは言い切れません。
実際に経験の蓄積があるのだから、それを分析すべきでしょう。
僅かなといいつつ、フラグのフィールドなんかが追加になってたら、
それはもう業務ロジックが変わっているのでは?
データ層の修正のみに収まりそうな事例があったなら、もう少し
具体的なサンプルデータを出してもらえませんか。
三層構造が特に重要視されるWEB アプリでも、ビジネスロジック
層はアプリケーションサーバ上に置かれる事が多いと思います。
ここは特に重要で、WEB アプリの場合、データベースの構造及び
業務ロジックに関する情報はサーバ外に漏れないようにします。
アプリケーション層との完全な分離ですね。
セキュリティ面と、修正が発生した場合に、その範囲をサーバ内
に収める為です。
アプリケーション層とビジネスロジック層の分離で悩む事は多い
ですが、データ層は本当に既存クラスで収まると思ってました。
> エンティティクラス
必要だとしても、DataRow あたりで十分だと思うんですが。。。
> Oracleが多いのでチューニングが行い難くなると致命的かもしれません。
これも、よくある実行計画の分析なんかだと、SQL そのものが
がらりと変わる場合があると思います。下手にデータ層に
入れ込まないほうが良いんじゃないかなぁ。
クラス作るより先に、既存クラスをもっとよく見るべきかも。
ほぼそのまま利用すれば良いものも多いのでは?
究極の汎用的ってのは、自作クラス数0の事だと思います。
いつもこの問題で悩んでしまいます。
データベースクラス
このクラスでは、データベースへの接続・切断の状態管理用クラスです。
業務ロジッククラス
データベースクラスと連携し、必要な値を生成・加工・変更するクラスです。
フォームクラス
業務ロジッククラスの作成元のクラスです。
このクラスでは、フォーム上の各コントロールへの値セットや変更を行います。
質問:業務ロジッククラスからデータベースクラスへのパラメータクエリを使用し
DML文等を作成する場合はどのようにしたら良いでしょうか?
このような3つのクラスがあり、データベースから値を得たい場合
業務ロジッククラスからDML文を作成しクエリを発行しなければ
ならないと思います。
この時、データベースに対し業務ロジック側からパラメータクエリで
DML文等を作成したいのですが、
例えば、OleDbを使用しているとするならばOleDbCommandに対しパラメーターを
追加しなけばなりません。
その場合に、業務ロジック側から作成するのであればOleDbCommandのスコープは
最大限に拡げねばならなくなります。
かといってデータベースクラスにパラメータクエリ用のメソッド等を用意した場合
データベースのフィールドを直に指定しなければなりません。
そのようにすると再利用性が失われる為好ましくありません。
何か良い方法やパターンはありますか?
宜しく御願いします。