しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

今すぐ Entity Framework 6 で使える機能と Entity Framework 7 についてまとめた

富山で某 O 江さんが Entity Framework 4 で切り捨てたと言ってたので、最新の Entity Framework 6.1.2 について書きます。割と頑張っているし、Entity Framework 7 が期待出来そうです。

EF6.1.2 RTM Available - ADO.NET Blog - Site Home - MSDN Blogs

Entity Framework 6 に関しては今後はバグ修正レベルのアップデートになりそうです。ASP.NET 5 と同じタイミングで Entity Framework 7 をリリースしないといけないので大変なのでしょう。

それでは使えないと思われがちな機能を紹介していきます。

コードファーストのモデルクラスを DB から自動生成する

コードファーストのモデルクラスという表現はいまいちですが、DbContext を使う POCO エンティティを DB から自動的に生成するテンプレートが Visual Studio に用意されてます。

EDM を追加する際にコードファーストの選択肢が出てくるので、選んで行けば OK です。

f:id:shiba-yan:20150202211712p:plain

当然ながら DB を選択する必要があるので、適当にサーバーを選んで DB を選びます。同時に接続文字列名をわかりやすい名前でいれておくといい感じです。

f:id:shiba-yan:20150202211726p:plain

最後にクラスを生成するテーブルを選択できるので、必要なテーブルだけ選んでおきます。

f:id:shiba-yan:20150202211735p:plain

これで必要な DbContext とモデルクラスが生成されます。手書きは DB 無しスタートの開発で十分です。

f:id:shiba-yan:20150202212119p:plain

テーブル数が多いと当然ファイル数も増えるので、適当なフォルダに入れておくのが良いです。

実行される SQL を出力する

昔はめんどくさかった SQL のログ出力がとても簡単になりました。Database.Log プロパティにどっかに出力するデリゲートを入れておけば勝手に呼び出されます。

var context = new AdventureWorks();

context.Database.Log = p => Debug.WriteLine(p);

var ids = new[] { 1, 2, 3, 4, 5, 6, 7, 8 };
            
var list = context.Products.Where(p => ids.Contains(p.ProductID)).Select(p => new
{
    p.Name,
    p.ModifiedDate
}).ToArray();

このコードを実行すると Visual Studio の出力ウィンドウにログが出力されます。

f:id:shiba-yan:20150208000502p:plain

ちゃんと Contains は IN にマッピングされて実行されていることが確認できますね。

ストアドプロシージャ・テーブル値関数を使う

コードファーストでは自動でマッピングされませんが、EDMX を使って DB からモデルを自動生成する時にストアドやテーブル値関数を DbContext に追加できるようになってます。

f:id:shiba-yan:20150202220030p:plain

DbContext に定義されているテーブル値関数は、特に深く考えることなく LINQ 内で参照できます。

var context = new AdventureWorksLTEntities();

var list = context.Customers.Count(p => context.ufnGetCustomerInformation(p.CustomerID).Any());

この場合では以下のような SQL が実際に実行されます。SELECT が一個余計だと思いますが、テーブル値関数の呼び出しにマッピングされていることが分かります。

SELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        COUNT(1) AS [A1]
        FROM [SalesLT].[Customer] AS [Extent1]
        WHERE  EXISTS (SELECT 
            1 AS [C1]
            FROM [dbo].[ufnGetCustomerInformation]([Extent1].[CustomerID]) AS [Extent2]
        )
    )  AS [GroupBy1]

パフォーマンスや SQL のクオリティはともかくとして、Entity Framework 6.1.2 では LightSpeed 5 とほぼ同じことを実現出来るようになったみたいです。

Entity Framework 7 について

新しい ASP.NET 5 向けに Entity Framework 7 が GitHub 上で開発されています。現状の Entity Framework 6 が .NET Core 上で動かすことが出来ないみたいで、割と急ピッチでの開発になっているようです。

無効化されていますが、Universal Windows App でも将来的に動作するように開発が進められています。

Entity Framework 7 では Azure Table Storage に対応する話 - しばやん雑記 を書いた時には Azure Table Storage への対応が追加されていたのですが、現在は dev ブランチから綺麗に消滅しています。Redis に関しても消えているので、まずは RDB への対応をしっかりと行うことにしたようです。

f:id:shiba-yan:20150202212008p:plain

その代わりに EntityFramework.Relational という RDB 向けのライブラリが追加されています。SQL Server 以外への対応が容易になる可能性がありそうです。

期待できる点としては、Entity Framework 7 では生成される SQL のクオリティが結構改善しているようです。ポルトガル語ですが、Entity Framework 6 と 7 で生成される SQL を比較している記事を見つけました。

Examinando as queries geradas pelo Entity Framework 7 | akaMud – Blog

紹介されているケースでは Entity Framework 6 に比べて大幅に改善されていることが分かります。

Nightly Build でも試してみたかったんですが、ログ周りが大きく変わっていて方法が分からなかったので、また今度試してみようかと思います。