はじめに

まずは基本編などで説明したコードを挙げ、それを元に説明します。
VB.NET
0:  Imports Kairyu.Extensions.IO
0:  Imports Kairyu.Load
・・・
1:  Dim lst As List(Of Prefecture) = Nothing
2:  DB.Connect(
3:      Sub(r As ModelLoader)
4:          lst = r.From(Of Prefecture) _
5:              .ToList
6:      End Sub)
  • ORMのコードを記述するときは、拡張メソッドを使用するために「Kairyu.Load」をインポートしておいてください。

3行目に「ModelLoader(変数名 r )」が出てきますが、これがR/Oマッピングを行うための起点になるクラスです。
このModelLoaderクラスのR/Oマッピング処理を簡単に記述すると以下のようになります。
  • ModelLoaderがマッピングを行ったObjectはユニークな名前を付けて辞書に登録します。
  • 新しくマッピングを開始する場合、上述の辞書に存在する場合は辞書のインスタンスを返却し、マッピング処理をスキップします。
  • 辞書に存在しなかった場合は、新規にマッピング処理を行い、辞書に登録します。

キャッシュの登録と破棄のタイミング

実用性はともかく、具体例を挙げます。
VB.NET
Imports Kairyu.Extensions.IO
Imports Kairyu.Load
・・・
Dim m1 As Prefecture = Nothing
Dim m2 As Prefecture = Nothing
DB.Connect(
    Sub(r)
        m1 = r.From(Of Prefecture).WhereEquals(Function(x) x.PrefectureName, "東京都").ToItem
        m2 = r.From(Of Prefecture).WhereEquals(Function(x) x.PrefectureName, "東京都").ToItem
    End Sub)
Debug.Print(m1.Equals(m2)) 'True
変数m2がm1と同じであることに注目してください。
m2はマッピングを開始したとき、r(ModelLoaderクラス)内に既にm1のインスタンスキャッシュがあったので、m1のインスタンスを返却しているために起こる症状です。

もう1つ例を挙げます。
VB.NET
0:  Imports Kairyu.Extensions.IO
0:  Imports Kairyu.Load
・・・
1:  Dim m1 As Prefecture = Nothing
2:  Dim m2 As Prefecture = Nothing
3:  DB.Connect(
4:      Sub(r)
5:          m1 = r.From(Of Prefecture).WhereEquals(Function(x) x.PrefectureName, "東京都").ToItem
6:      End Sub)
7:  DB.Connect(
8:      Sub(r)
9:          m2 = r.From(Of Prefecture).WhereEquals(Function(x) x.PrefectureName, "東京都").ToItem
10:     End Sub)
11: Debug.Print(m1.Equals(m2)) 'Flase
先程の例とほぼ同じですが、今回は変数m2がm1と同じではないことに注目してください。
これはModelLoaderはDB.Connectメソッドを抜けた時に廃棄されるので、m1のマッピングに使用したキャッシュは、6行目を抜けた時になくなります。よって、m2は新しくインスタンスされることとなり、m1とm2は同じインスタンスではないということになります。

目的

上層へリレーションした場合、DBMS上同一のデータが、Object上複数存在する可能性があります。
この「複数存在する」というのをメモリ上複数存在させるのはもったいないですし、また整合性も維持できなくなるので、インスタンスを同一化したいという思惑があります。

実例

わかりづらいので、リレーションを使用した例を挙げます。
モデル(VB.NET)
Public Class Article
    Public Property ArticleID As Integer
    Public Property ArticleName As String
    Public Property ArticleGroup As ArticleGroup
End Class
Public Class ArticleGroup
    <AutoKey()>
    Public Property ArticleGroupID As Integer
    Public Property ArticleGroupName As String
End Class
このモデルは、商品は1つの商品グループに属しているというリレーションを表しています。
データは以下のようになっているものとします。

Articlesテーブル
ArticleID ArticleName ArticleGroupID
1 Apple 1
2 Orange 1
3 Grape 1

ArticleGroupsテーブル
ArticleGroupID ArticleGroupName
1 Fruits
2 Vegetables


このテーブルをカスケードを機能を使って一括読み込みしてみます。
VB.NET
Imports Kairyu.Extensions.IO
Imports Kairyu.Load
・・・
Dim lst As List(Of Article) = Nothing
DB.Connect(
    Sub(r)
        lst = r.From(Of Article)(limitLevel:=-1).WhereKeyEquals({1, 2}).ToList
    End Sub)
Debug.Print(lst(0).ArticleGroup.Equals(lst(1).ArticleGroup)) 'True
Articleの上層にあるArticleGroupが、「Apple(ArticleID=1)」と、「Orange(ArticleID=2)」で同じインスタンスになっていることに注目してください。
これは以下のように処理されていることによります。
  1. ArticleID=1のArticleクラスマッピングを開始。インスタンスキャッシュには存在しないため、新規にインスタンス。
  2. ArticleID=1のArticleクラスマッピングが終了。インスタンスをキャッシュに登録。
  3. ArticleID=1のArticleGroupクラスマッピングを開始。インスタンスキャッシュには存在しないため、、新規にインスタンス。
  4. ArticleID=1のArticleGroupクラスマッピングが終了。インスタンスをキャッシュに登録。
  5. ArticleID=2のArticleクラスマッピングを開始。インスタンスキャッシュには存在しないため、新規にインスタンス。
  6. ArticleID=2のArticleクラスマッピングが終了。インスタンスをキャッシュに登録。
  7. ArticleID=2のArticleGroupクラスマッピングを開始。インスタンスキャッシュには存在する(4にて登録されている)ため、キャッシュを再利用。
  8. 終了

Last edited Mar 12, 2013 at 4:05 PM by mk3008, version 4

Comments

No comments yet.