読者です 読者をやめる 読者になる 読者になる

VB.NETで作る!

VB.NETに関するあれこれ

O/Rマッパー Kairyu ver.0.5.0.0

ORマッパー Kairyu 0.5 がほぼ形になったので公開。

Kairyu とは

コネクションを隠蔽しないシンプルなO/Rマッパーです。 単調かつ大量に発生するObject Relation変換コーディングを減らすために作られました。

ver0.5はver0.3の内容をフルスクラッチ、仕様見直ししてますので、まだCodePlexへは反映させてません。

概要

  • 名前空間大幅に見直し。
  • ダーティチェックとORマッピング処理を切り離し。
  • コネクション処理を完全に切り離し。

機能

全般

  • クラス名・テーブル名の変換処理を任意に差し替え可能
  • プロパティ名・列名の変換処理を任意に差し替え可能
  • 主キー列命名規約変更可能

読み込み

  • 主キー検索対応
  • 全件取得対応
  • 無制限上層カスケード対応
  • 上層カスケード階層数の指定可
  • 外部結合対応
  • 1階層下層読み込み対応
  • 基底クラスを別テーブルに分離可能

書き込み

  • シーケンス対応
  • カスタムキー生成対応
  • バージョンキー対応(楽観的排他制御
  • 無制限下層カスケード対応
  • ダーティチェック対応
  • オートナンバー対応
  • 追加・更新タイムスタンプ対応
  • 追加・更新システム情報対応(追加者、更新者などの情報)

そのほか

SQLServerのみDDLサポート(ユニットテスト上必要だったので)

使い方

全文を載せるとさすがに冗長ですので、イメージにのみ記載。 詳しくは添付ファイルのユニットテストコードを参照してください。

モデル定義

主キーにマッピングされるプロパティの名前はクラス名+”ID”の命名規則に合わせる必要があります。*1 命名規則に合わない場合はKey属性をつけることでキーと判断させることができます。

Public Class Test
    Public Property TestID As Integer
    Public Property TestName As String
    Public Property Lowers As ICollection(Of LowerTest)
End Class

Public Class LowerTest
    <Key>
    Public Property Test As Test
    Public Property LowerTestID As Integer
    Public Property LowerTestName As String
End Class

DB接続

これが基本になります。 ModelLoaderクラスにIDbConnectionを参照できるプロパティがありますので、 ORMを使用しないクエリを実行する場合はそちらからIDbCommandを作成してください。

Dim DB As New SqlServerDB("Data Source=.\SQLEXPRESS;Initial Catalog=tempdb;Integrated Security=True")
DB.Connect(
    Sub(r As ModelLoader)
        'Any Code
    End Sub)

DDLSQLServer

第1引数にコネクション、第2引数にテーブルを作成したい型を渡す。 第2引数には型は配列可です。

DB.Connect(
    Sub(r)
        SqlServer.TableCreater.Execute(r.Connection, GetType(Test))
    End Sub)

IF EXISTS (SELECT * FROM sysobjects WHERE name='Test' AND xtype='U') DROP TABLE Test;
CREATE TABLE Test (TestID int NOT NULL, TestName nvarchar(200) NOT NULL,CONSTRAINT PK_Test PRIMARY KEY(TestID));

全件検索

Dim lst As List(Of Test) = Nothing
DB.Connect(
    Sub(r)
        lst = r.Load(Of Test).ToList
    End Sub)

SELECT T0.TestID T0_0, T0.TestName T0_1
FROM Test T0

主キー検索

実際にはパラメータクエリが実行されてますが、イメージとしてハードコーディングした場合のSQLを併記します。

Dim c As Test = Nothing
DB.Connect(
    Sub(r)
        c = r.Load(Of Test)(New Test With {.TestID = 1}).ToItem
    End Sub)

SELECT T0.TestID T0_0, T0.TestName T0_1
FROM Test T0
WHERE T0.TestID = '1'

上層カスケード読み込み

FullCascadeで無制限上層カスケードになります。 階層を指定したい場合はCascade(level As Integer)で指定します。 なお、level=0とすると、カスケードなし。level=1とすると、1階層のみ上層へカスケードします。

DB.Connect(
    Sub(r)
        c = r.Load(Of Test)(New Test With {.TestID = 1}).FullCascade.ToItem
    End Sub)

SELECT T0.TestID T0_0, T0.TestName T0_1, T0.Layer2ID T0_2, T0.NullLayer2ID T0_3, T1.Layer2Name T1_1, T1.Layer3ID T1_2, T2.Layer3Name T2_1
FROM Test T0
INNER JOIN Layer2 T1 ON T0.Layer2ID = T1.Layer2ID
INNER JOIN Layer3 T2 ON T1.Layer3ID = T2.Layer3ID
WHERE T0.TestID = '1'

下層カスケード読み込み

下層は一括では取得できないので、2段階に分けて読み込みします。

DB.Connect(
    Sub(r)
        c = r.Load(Of Test)(New Test With {.TestID = 1}).ToItem
        c.Lowers.ToQuery.FullCascade.Fetch()
    End Sub)

SELECT T0.TestID T0_0, T0.TestName T0_1
FROM Test T0
WHERE T0.TestID = '1'
/   
SELECT T0.TestID T0_0, T0.LowerTestID T0_1, T0.LowerTestName T0_2
FROM LowerTest T0
WHERE T0.TestID = '1'

追加

トランザクション処理になりますので、Transactを使用してDBにアクセスします。 ModelSaverはModelLoaderを継承していますので、上述に挙げた読み込み処理も実行可能です。

DB.Transact(
    Sub(r As ModelSaver)
        r.SaveAsNew(New Test With {.TestID = 1, .TestName = "Test1"})
    End Sub)

INSERT INTO Test (TestID, TestName) VALUES ('1', 'Test1')

削除

DB.Transact(
    Sub(r)
        r.SaveAsDelete(New Test With {.TestID = 1})
    End Sub)

DELETE FROM Test WHERE TestID = '1'

更新

ダーティチェックをするためにStorageクラスに現状を記憶させておく必要があります。 SaveメソッドはStorageに登録されているアーカイブ値をもとに、自動的に追加・更新・削除処理が行われます。 下層カスケードもサポート。

DB.Connect(
    Sub(r)
        c = r.Load(Of Test)(New Test With {.TestID = 21}).ToItem()
        c.Lowers.ToQuery.Fetch()
    End Sub)

Dim s As New Storage(c)

c.Lowers.Remove(c.Lowers.First)
c.Lowers.First.LowerTestName = "Update"
c.Lowers.Add(New LowerTest With {.LowerTestID = 3, .LowerTestName = "Add"})

DB.Transact(
    Sub(r)
        r.Save(s.ToDirtyObjects(c))
    End Sub)

INSERT INTO LowerTest (TestID, LowerTestID, LowerTestName) VALUES ('21', '3', 'Add')
/
DELETE FROM LowerTest WHERE TestID = '21' AND LowerTestID = '1'
/
UPDATE LowerTest SET LowerTestName = 'Update' WHERE TestID = '21' AND LowerTestID = '2'

*1:命名規則を変えることは可能。

. .