ドメインモデルをLINQで構築する

まだまだLINQについて調べたいことはたくさんあるが、とりあえず、いくつかのドメインモデルのパターンを作成したので振り返りまとめとします。

ORMとしてLINQ to SQL

一言でいってよくできたORMフレームワークです。
Expression TreeをSQLに変換するアイデアは、直前まで実行を遅延することができより的確なSQL文を発行できる点や、Expression TreeをQuery Objectとしてビジネスロジックで検索条件を記述でき・しかも型付きである点などは便利だと感じました。また、オブジェクト更新などのトラッキング機能や今回書きませんでしたがオブジェクトのキャッシュ機能など細かな点もよく考えられています。個人的には複数のテーブルにまたがるオブジェクトの読み出しや永続化のより細かな制御が行えるようにもう少し強化してもらいたい点はありますが汎用的なORMとしてはこのあたりが妥当なレベルなんでしょう。ただ、現在のORMの考え方を変えるようなより強烈な仕組みがあってもよかったのかとも思っています。ドメインモデルを主にしてデータベースを生成するような仕組みとか...

めっちゃ便利なLINQ to Object

LINQを使うとオブジェクトに対する集合演算が簡潔に書け便利です。ビジネスルールも変な名前を付けるのであればLINQで表現した方が分かりやすいのではと感じるぐらいです。また、LINQ to SQLで利用する式をオブジェクトに対して利用できる点も便利で、LINQ to SQLの検索結果をキャッシュしLINQ to Objectでより高度な検索を行うなどドメインモデルでの利用には威力を発揮しました。これなしでプログラムを書くことはできなくなりそうです。

オブジェクトのキャッシュ機能(おまけ)

LINQ to SQLにはオブジェクトをキャッシュする機能が備わっていてID(PK)が同じエンティティを読み出した場合自動的にキャッシュされた同じIDのエンティティがあればそのオブジェクトを返してくれるようです。

以下のテストケースは全て成功します。ちなみにどのようなSQL文が発行されるかは各自で確認してみてください。この特性を利用してエンティティを先読みすることも可能のようです。

[TestMethod]
public void TestCache1()
{
    using (var db = new BurgerShopDBDataContext())
    {
        db.Log = Console.Out;
        var shop1 = db.Shops.First(p => p.ShopID == 1); // OSAKA店
        var shop2 = db.Shops.First(p => p.ShopID == 1); // OSAKA店
        Assert.IsTrue(shop1 == shop2);
    }
}

[TestMethod]
public void TestCache2()
{
    using (var db = new BurgerShopDBDataContext())
    {
        db.Log = Console.Out;
        var shop1 = db.Shops.First(p => p.ShopID == 1); // OSAKA店
        var shop2 = db.Shops.First(p => p.Name == "OSAKA");
        Assert.IsTrue(shop1 == shop2);
    }
}

[TestMethod]
public void TestCache3()
{
    using (var db = new BurgerShopDBDataContext())
    {
        db.Log = Console.Out;
        var shop1 = db.Shops.First(p => p.ShopID == 1); // OSAKA店
        shop1.Tel = "";
        var shop2 = db.Shops.First(p => p.Name == "OSAKA");
        Assert.AreEqual("", shop2.Tel);
    }
}

[TestMethod]
public void TestCache4()
{
    using (var db = new BurgerShopDBDataContext())
    {
        db.Log = Console.Out;
        var shop1 = db.Shops.First(p => p.Name == "OSAKA");
        var shop2 = db.Shops.First(p => p.ShopID == 1); // OSAKA店
        Assert.IsTrue(shop1 == shop2);
    }
}