SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Visual StudioでDB連携も簡単プログラミング ~知っておきたいLINQメソッド式&ラムダ式

LINQにも色々 ~SQLに変換されるモノと変換されないモノ

Visual StudioでDB連携も簡単プログラミング-知っておきたいLINQメソッド式&ラムダ式 第4回

  • X ポスト
  • このエントリーをはてなブックマークに追加

 本連載では、データベースプログラミングにおいてLINQをどのように活用できるのか、解説していきます。前回の記事では、Entity Frameworkが出力するSQLを確認し、N+1問題と呼ばれる、遅延ローディングに伴って発生するパフォーマンス上の問題への対応方法を確認しました。連載最終回となる今回は、LINQがSQLに変換される仕組みについて、もう少し細かく追って行きましょう。

  • X ポスト
  • このエントリーをはてなブックマークに追加

LINQにも色々

 LINQからSQLへの変換について説明するにあたり、LINQのバリエーションについて少し解説しておきます。第1回で説明したとおり、LINQの対象は、配列・コレクション・データベース・XMLなど多岐にわたっています。これまでLINQとしてひとくくりに扱ってきましたが、クエリ対象によって幾らかのバリエーションがあります(表1)。

表1 LINQの様々なバリエーション
LINQの種類 クエリ対象
LINQ to Objects 配列・コレクションなど、任意のオブジェクト
LINQ to Entities Entity Framework経由でデータベース(SQL Server/Oracle/MySQL/SQLite等)
LINQ to XML XML
LINQ to SQL SQL Server

 過去2回のデータベースプログラミングで解説してきたのは、Entity Framework経由でデータベースにアクセスするLINQ to Entitiesです。XMLを対象とするLINQ to XMLはやや毛色が異なるため本連載では扱いません。また、LINQ to SQLは、Entity Framework登場以前に使われていたSQL Server専用の機能のため、こちらも割愛します。

SQLに変換されないモノ

 さて、LINQについて紹介する記事では、配列やコレクションなどをクエリ対象とするLINQ to Objectsを使って解説されることが多いのですが、実はLINQ to ObjectsとLINQ to Entitiesには違いがあり、LINQ to Objectsでは普通に動くLINQが、LINQ to Entitiesでは動かない、というケースがしばしば生じます。

 たとえば、リスト1はLINQ to Objectsで、文字列長が6かどうかでフィルタするサンプルです。

リスト1 LINQ to Objectsで自分で定義したメソッドを呼んでみる
//LINQ to Objects クエリ対象文字列配列
string[] names = { "Doi", "Tanaka", "Nakamura", "Saitou", "Yamada" };

//①文字列長6のものだけ取り出す
var query = names.Where(x => x.Length == 6);
//出力結果:Tanaka,Saitou,Yamada
Console.WriteLine(string.Join(",", query));

//②条件をIsLength6メソッドに置き換えてみる
query = names.Where(x => IsLength6(x));
//出力結果は変わらない
Console.WriteLine(string.Join(",", query));

//文字列の長さが6かどうかを判別するメソッド
private bool IsLength6(string str)
{
  return str.Length == 6;
}

 ①では普通にラムダ式を使っているのに対し、②では自分で定義したIsLength6メソッドを使っています。「文字列の長さが6かどうか」という検索条件は変わりませんので、当然出力結果は同じです。

 続いて同じようにLINQ to Entitiesで書いてみましょう(リスト2)。

リスト2 LINQ to Objectsで自分で定義したメソッドを呼んでみる
//①シンプルに文字列長でフィルタ
products = context.Products.Where(x => x.Name.Length == 6);
DumpProducts(products); //問題無く出力される

//②IsLength6メソッドを使う
products = context.Products.Where(x => IsLength6(x.Name));
DumpProducts(products); //例外発生!!!

 今度は不可解な結果となりました。①のWhereメソッドは「WHERE 6 = ( CAST(LEN([Extent1].[Name]) AS int))」のようなWHERE文の付いたSQLに正しく変換され、その後の処理にも問題はありません。一方自分で定義したIsLength6メソッドを使った②では、System.NotSupportedException例外が発生します。①と②は処理内容としてはそれほど変わったように見えないのですが、何が違うのでしょうか?

 NotSupportedException例外のメッセージを見ると、「メソッド 'Boolean IsLength6(System.String)' は LINQ to Entities では認識されないため、ストア式に変換できません。」とあります。やはりIsLength6というメソッドがLINQ to Entitiesでは認識されず、使用することができないようです。

 「LINQ to Objectsで動くのに、LINQ to Entitiesで動かないなんて……」と気を落とすことはありません。この違いは、図1のように、LINQ to ObjectsとLINQ to Entitiesでは、LINQが実際に実行される方法の違いによって発生します。

図1 LINQ to ObjectsとLINQ to Entitiesの実行方法の違い
図1 LINQ to ObjectsとLINQ to Entitiesの実行方法の違い

 LINQ to Objectsでは、LINQがそのまま、C#のプログラムと同様に実行されます。そのため、LINQの中から自分が定義したメソッドなどを自由に呼び出すことができます。一方、LINQ to Entitiesでは、LINQはSQLに変換され、データベース上で実行されます。そのため、元々のC#プログラム内で定義したメソッドなどをLINQの中から呼び出すことはできません。つまり「LINQ to Entitiesで使用する機能はすべてSQLに変換可能でなければならない」のです。仕組みを考えてみると当たり前ではあるのですが、LINQに慣れて、色々なクエリを試すようになると、引っかかりやすいポイントでもあります。

会員登録無料すると、続きをお読みいただけます

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

次のページ
SQLに変換されるモノ

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Visual StudioでDB連携も簡単プログラミング ~知っておきたいLINQメソッド式&ラムダ式連載記事一覧

もっと読む

この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

WINGSプロジェクト 土井 毅(ドイ ツヨシ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/8474 2015/03/06 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング