Entity Framework と Linq を使いこなしたい!

こんにちは、最近忙しい、和朗です。

今回は、現在利用しており今後も利用することになるであろう、EF6 と Linq について書いてみようと思います。

SQLのLog出力

これはなくてはならない機能! EFから発行されたSQLを簡単に見ることができます。SQL発行のタイミングもわかるので便利ですね。

[TestMethod]
public void TestMethod1()
{
    using (var db = new BlogContext())
    {
        // 出力>デバッグにSQLを表示
        db.Database.Log = x => System.Diagnostics.Debug.WriteLine(x);
        System.Diagnostics.Debug.WriteLine("Blogs:{0}件", db.Blogs.Count());
    }
}

ログ出力

Opened connection at 2015/08/31 18:21:50 +09:00

SELECT
`GroupBy1`.`A1` AS `C1`
FROM (SELECT
COUNT(1) AS `A1`
FROM `Blogs` AS `Extent1`) AS `GroupBy1`


-- Executing at 2015/08/31 18:21:50 +09:00

-- Completed in 4 ms with result: EFMySqlDataReader


Closed connection at 2015/08/31 18:21:50 +09:00

Blogs:495件

.AsNoTracking()

SQLにwith(nolock)をつけているイメージ。更新の必要の無いデータにアクセスする場合はAsNotrackingを利用したほうがパフォーマンスがアップするようです。

[TestMethod]
public void TestMethod2()
{
    using (var db = new BlogContext())
    {
        var data = db.Blogs.AsNoTracking().Where(b => b.name = "1");
        foreach (var item in data)
        {
            System.Diagnostics.Debug.WriteLine("{0}:{1}", item.name, item.context);
        }

    }
}

Entity Framework and AsNoTracking←パフォーマンスについては、2-3割ぐらい早くなるようですね。

遅延評価を利用しない

ToArray()を利用することでSQLを発行し、結果を確定させる。 ToArrayした後のオブジェクトにアクセスしても、SQLが発行されることはない。 実際は遅延評価を利用しない訳ではなく、任意のタイミングで評価させる。 IEnumerable以外の型に変換する、もしくは、IEnumerableからデータを取り出すと評価が実行される。

[TestMethod]
public void TestMethod3()
{
    using (var db = new BlogContext())
    {
        var data = db.Blogs.ToList();
        var dataArray = data.ToArray();
        var dataA = data.Select(~~);
        var dataB = dataArray.Select(~~);        
    }
}

.Skip() と .Take()

一覧表示を行う際に必要となってくるページング処理で利用します。 Whereでデータを絞ったあとに、.OrderBy()を行い、必要なデータを取得します。

[TestMethod]
public void TestMethod4()
{
    var pageSize = 20;
    var pageIndex = 3;
    using (var db = new BlogContext())
    {
        var data = db.Blogs.Where(~~~);
        var target = data.OrderBy(x => x.id)
            .Skip(pageSize * (pageIndex)).Take(pageSize);
    }
}

大文字小文字の区別

SQLSERVERの照合順序はデフォルト大文字小文字を区別しないため、注意が必要。 私は以前、パフォーマンスアップのためにSQLからLinqにリファクタを行ったはずが結果セットが一致せず、悩みました。もちろんLinqは大文字小文字を区別します。

[TestMethod]
public void TestMethod5()
{
    using (var db = new BlogContext())
    {
        var data = db.Blogs.Where(b => b.name.Lower().Contains("a"));

    }
}

まとめ

EF6になって全体的なパフォーマンスはアップしたと聞きますが、 SQLを書くときと同様にパフォーマンスを意識したコードが必要だと感じます。 ちょっとした実装方法の違いで劇的にパフォーマンスが悪くなったりするので、Logを見ながら改善が必要ですね!