@ledsun blog

無味の味は佳境に入らざればすなわち知れず

DAOの詳細設計 C#編

J2EEパターンから始まって今となっては一般的になったDAOパターン、の詳細設計。

DTO

DTOは更新時間、更新ユーザ以外のテーブルカラムをすべて持たせる。

  • カラム名とプロパティ名を対応させておくとINSERTとUPDATEのSQLを動的に生成できて楽。
  • マスタメンテナンス画面なんかは削除中も表示することがあるので削除フラグも持たせる。
ゲッターはpublic

次の実装が楽

  • IDの差し替え
  • 特定カラムの更新
セッターはprivate

コンストラクタで指定すれば、カラムの増減があった際に修正個所をコンパイルエラーで拾える

DAOのメソッド

次のようなメソッドを一律用意しておくと大体なんとかなる*1。何とかならない場合は個別に追加すればよい*2
前提

  • 更新ユーザはDAOの引数で受け取る
  • 更新時間はDAOで現在時刻を取得して更新する
  • 更新件数を戻すとテストしやすい
C

1件Insert

public int Insert(Dto dto, string updateUser, Tran tr, int pk1 = 0, int pk2= 0);

メソッド内でID発番

public int InsertNewId(Dto dto, string updateUser, Tran tr);
  • IDが連番などで、DAO(またはシーケンス)で発番する場合

複数件Insert

public int Insert(IEnumerable<Dto> dto, string updateUser, Tran tr, int pk1 = 0);
  • ビジネスロジックで発番する場合はPKを指定する
  • PK指定が無ければDTOの値をそのままINSERTする
    • テーブルAからテーブルBへレコードを複数件移動する場合は、DTOをそのまま入れたい

メソッド内でID発番

public int InsertNewId(IEnumerable<Dto> dto, string updateUser, Tran tr, int pk1);
  • 単票のリスト項目など、親PKだけ指定して枝番はメソッド内(またはシーケンス)で発番すればよい
R

ID指定して取得

public IEnumerable<Dto> SelectById(int pk1, int pk2, Tran tr = null);

全件取得

public IEnumerable<Dto> SelectAll(Tran tr = null);
  • 主にマスターテーブル用
    • 表示件数に上限があるなど、メモリ上に大量のデータを作らないならどんなテーブルで使っても可
  • 論理削除されている項目の絞り込みはビジネスロジックでやればよい

枝番PKの最大値を返す

public int SelectMaxId(Tran tr = null);

その他

  • 名前での検索は物理テーブルに依存するのでそれぞれ作る
  • 親子関係をDTOにマッピングする場合はメソッド内で行う
    • JOINしたSQLを発行して一気にマッピングするのは複雑な割にメリットが少ないのでおススメしない。チューニングとしては有りなのでその場合は個別に実装。
  • トランザクションをデフォルト引数で指定できると便利
U

特に変わったことをすることがない

public int Update(IEnumerable<Dto> dto, string updateUser, Tran tr);
D

物理削除は次ぐらいしかない

  • リスト項目のDelete/Insert
  • テストデータの削除

リスト項目のDelete/Insert

public int DeleteByParentId(int pk1, Tran tr = null);
  • 単票のリスト項目などは親PKを指定してDELETEしたい

テストデータの削除

public int DeleteByUpdateUser(string updateUser, Tran tr = null);
  • テスト用のレコードを特定のユーザIDで入れておくと一括で削除できて楽

*1:可能なT4テンプレート使って自動生成するとよい、という意味

*2:自動生成する時にSELECT文とDTOへの変換メソッドを分けておくと便利