LINQ

17 posts

LINQ to DataSet

[LINQ to DataSet]については、VS2008のドキュメントにかなり詳しく書かれています。

話は変わりますが(突然)、あることについて初めて勉強するときに、コンピュータ画面は不向きだと思います。
ちょっとしたことを調べる、あるいは大体は知っていることについて確認する場合は、画面の方がいいかも知れません。
コンピュータの新しい技術を勉強するとき、一度流して読んだだけでは理解しがたいときが間々あります。
この場合以前読んだ部分を何度も読み返しことになりますが、この読み返す操作では画面は大変カッタルク、書籍がはるかに勝ります。

そんな訳で[LINQ to DataSet]のVS2008のヘルプは、初めての勉強には不向きです。


以前紹介した[murach’s ADO.NET 3.5 LINAQ and the Entity Framework with VB2008]が入門としては最適(私の持ち合わせの中では)だと思います。ここでは[LINQ to DataSet]に一章を割いていて、概要を知るには最適だと思います。

さて、最初VS2008のドキュメントで手探りでVB6のバージョンアップのコードを書いていたのですが、murach’sを読んで大きく間違ってはいなかったと確認しました。

Entity Framework と MyDataBinding

LINQでは基本的に、厳密に型指定されたオブジェクトを使用します。これのいいところと悪いところがあります。

いいところは、タイプインの途中でインテリセンスがコーディングをサポートしてくれますので、ケアレスミスを防いでくれます。パフォーマンスも多少いいかも知れません。

ところがDBから抽出したデータをコントロールに表示したり、逆にコントロールのデータをDBに保存するときのコードが多少煩わしくなります。
この原因を作っているのは、私が[Data Binding]を嫌っているからです。.NETの[Data Binding]を信頼して使うのであればすべてがハッピーです。

私が[Data Binding]を嫌っているのは、(私が)この動きを十分にコントロールできないからです。私の予想を超えた動きをするので、「使えない」と(もしかして)勝手に思っているのです。また、[Data Binding]でFormatおよびParseを細かくプログラミングできない(と思っている)のも(しかも決定的)一因です。

[Data Binding]を使わないでデータをコントロールに表示するには、次のようにEntity(オブジェクト)のプロパティを一つずつコントロールのTextプロパティにアサインすることになります。

(いま、contextはEDMのインスタンス、BooksはこのEDMに含まれるEntitySet名、Title、AuthorおよびPriceはBook Tableの列名(=Entityのプロパティ名)とします。
また、画面にTextBox、txt書籍名、txt著者名およびtxt価格が配置されているとします。)

    Dim query = (From book In context.Books).First
    txt書籍名.Text = query.Title
    txt著者名.Text = query.Author
    txt価格.Text = query.Price

一般には画面には沢山のコントロールが配置されていますので、上のコードは書きたくありません。

ところでADO.NETでは次のように列名を文字列で書くことができます(いま検索した[DataRow]をdrとします)。

    txt書籍名.Text = dr("Title")
    txt著者名.Text = dr("Author")
    txt価格.Text = dr("Price")

したがって、コントロール[txt書籍名]と列名”Title”等のマップをあらかじめ作成しておけば、このマッピングを使ってコントロールのプロパティにアサインする仕組みを考えることができます。
例えば、このマッピングは9月18日、23日ブログで紹介しました[CtrlBindingCollection]を使います。

[CtrlBindingCollection]のメソッド[Display]を次のように定義します。
(正確ではありません。概念的な説明と理解してください。また以下で、[P_lst]、[P_Control]、[P_列名]はそれぞれ[m_lst]、[m_Control]、[m_列名]に対応したプロパティです。)

  Sub Display(ByVal dr As DataRow)
    For each c As Cell In P_lst
        c.P_Control.Text = dr(c.P_列名)
    End For
  End Sub

そうすれば、

    Dim CBC As New CtrlBindingCollection
    With CBC
     .Bind(txt書籍名, “Title”, “String”, True)
    .Bind(txt著者名, “Author”, “String”, True)
    .Bind(txt価格, “Price”, “Integer”, True)
    End With

(ここで、Bindメソッドの第一引数はコントロール、第二引数はそのコントロールに対応したDBテーブルの列名、第三引数はそのデータ型–説明のため”String”等の文字列で書いていますが、実際には独自に定義したデータ型のEnum値です–、第四引数はエンターキーで次のコントロールに移動するかどうかのフラグです)

を実行しておけば、

CBC.Display(dr)

でコントロールにデータを表示することができます(予めdrは読み込まれたDataRowだとします)。
逆にDB保存用のメソッドを作成することで、データのDBへの書き出しを一つのメソッドのコールで完了することができます。
この[CtrlBindingCollection]を十分練って汎用的にしておけば、このコレクションに登録したコントロールを一斉に操作することができます。

では、厳密に型指定されたオブジェクトを基本としているLINQではどうする。

先の例で、[txt書籍名]と [query.Title]とのマップを作ってみても何の役にも立ちません([txt書籍名]と dr(“Title”)
のマップを作っても役に立たないのと同じです)。
なぜなら、[query.Title]はインスタンスのプロパティですので(評価されて例えば”坂之上の雲”であり)、これと[txt書籍名]とのマップを保存してみても意味がないのです。

結論からいえば、解決策は[Programming Entity Framework]の17章に書かれています。

Entity Framework 奮闘記

LINQの勉強を始めたのは今年6月です。その後最新技法が[Linq to Entity]であると分かり、舵を[Entity Framework](以下EFといいます)の勉強に切り替えました。しかし[LINQ to Entity]の手ごろな教科書がありません。

LINQの勉強で4冊の本を買いました。

1. [プログラミング LINQ] Microsoft Press
2. [LINQ in Action] Manning
3. [Programming Entity Framework] O’Reilly
4. [murach’s ADO.NET 3.5 LINQ and the Entity Framework with VB 2008] Marach

2は教科書としてはよく書かれていますが、残念なことに2008年1月の出版ですので、昨年秋リリースされたEFの話題がありません。

1は和訳ですが、翻訳が悪いとの印象で必要な箇所の拾い読みをしています。原書は2008年の出版で、EFの解説が余りありません。訳書で付録としてEFの話題を追加していますが、どちらにしても入門程度の解説です。

4は各見開きの左ページは解説、右ページは表やコード、と徹底した構成になっていて、読みやすさを第一にしていますが、内容は入門程度です。

EFの解説書としては3が最適ですが、細かい字で構成も読みにくい。著者はおそらく教科書として書く気はまったくなく、「分かるやつは分かる」と至ってマイペースで書いていますので、私の力では800ページ弱のこの分厚い本を完全に理解するには半年程度必要かもしれません(当然勉強にいつまでも時間をとることはできません)。

しかし、考えてみればVisual Sdudioがもっともいい先生です。いつも文句も言わず根気よく私の解答の採点をしてくれます。ともかくプログラムを書いてVisual Sudioで格闘していれば大体話は分かってきます。

さて、こんな状態でともかくEFのプログラムを書いています。

LINQのいい点はDBアクセスプログラムが驚くほどが簡単に短くなったということ、
また、一度プログラムに読み込んだデータに対して、Queryを発行できますので(これはLINQの開発の目的のひとつでしょうが)、強力なデータ操作技術であることは間違いありません。

悪い点は(というより、困った点といった方がいいかも知れません)、一言で言えば「完成度が低い」ということです。
たとえば、ウィザードを使って[Entity Data Model](以下EDMといいます)を作成すると、データベースのテーブルに対応したクラスをプログラム上に作成します。この操作はデザイン画面で確認できますが、このモデルのメンテナンスがうまくない。
ウィザードで、あるテーブルをEDMに読み込んで、都合で削除したとします。再度そのテーブルをこのEMDに追加することができません。どうしてもこのEDMに入れたいのであれば、このEDMをゼロから再構築しなければいけません。これはこれで大騒ぎになります。

プロジェクトで一つのEDMだけ使うことにして全部のテーブルを読み込むのも一つの解決策かも分かりません。私は経験が少ないので、全部を一つのEDMにするのがいいかどうか分かりません。プロジェクトで数10以上のテーブルを使うのは珍しいことではないでしょう。
これを一度に一つのEDMにするのは、「パフォーマンスの点でどうなのか」、「大きなEDMのメンテナンスで手のつけられない大騒ぎになるのではないか」、逆にEDMを小割りにすると、EDM相互の関連が必要になったとき、また別の厄介な問題が発生し、どう処理するか。
どちらの道がいいのかまだ判断がつきません。

[LINQ to Entity]の勉強は何故か「しんどい」。たぶん理由のひとつは、[Object]とか[Entity]とか[Query]とかの普通名詞がいろいろ組み合わさって別の概念になっている。[ObjectEntity]とか[ObjectEnties]とか[ObjectEntry]とか[ObjectStateEntry]とか。何が何だか混乱します。

先にも書きましたが、現在もっともしっかり書かれた解説書は、Julia Lermanの[Programming Entity Framework] で、結局最後はこの本の解説を読むことになりますが、この本はEFの基本的枠組みの構成なりコンセプトなりのしっかりした解説をしないままに、多くの紙面を費やして様々な技術を解説していきますので、読むほうは「何がどうなっているのだ」としんどいばかりです。
来年になれば、もっといい教科書がでてくるのでしょうが、今はこの状態で進んでいくしかないのでしょう。

このブログでもEFをもう少し勉強して内容のあるお話を書ければと思います。

LINQ を使う

その後、[LINQ to Entity Framework]を使ってプロジェクトを進めています。

まだ、小学生程度の習熟度ですが、「総じてLINQはいい」というのが感想です(複雑なビジネスロジックの場合はどうなのか分かりません)。

私は、マイクロソフトが用意するデータバインドが気に入りません。
一言で言えば、カスタマイズについての柔軟性に欠けると思います。

具体的にいえば、データベースとコントロールでの表示の間に関数を入れたいのですが、どうすればいいのかよく分からない。たぶんできない(と思います)(もちろん、ストアドプロシージャを使うとかまったく方法がない訳ではありません。データバインドでのカスタマイズができません)。

したがって、データバインドを一切つかわないで、コントロールへの表示と、コントロールデータのデータベースへの格納の部分をすべてコーディングしています。

これを統一的に書くために、ADO.NETではコントロールとデータベースの列名のマップを定義していますが、LINQを使うと厳密に型づけされていますので、列名とEntity Objectとのマップをどう定義すればいいのかわかりません。

やむなくその都度、コントロールへの表示とデータベースへの保存をいちいち書いているというわけです。
ここが一番気にいらないのですが、Entity Frameworkをもっと研究すれば、解決策があるのではないかと思っています。

LINQのいいところは、先にも書きましたが、ADO.NETではデータベースへのコネクションを書き(忘れず終了し)、トランザクションを書き、複数テーブルを保存するときは、Insert、Update、Deleteとテーブルの依存関係を考慮したコードを書かなければいけません。

これらをLINQが全部やってくれるので、LINQのプログラミングはADO.NETに比べずいぶん楽です。

まだまだ研究中ですが、研究する価値が十分あると思います。

LINQ をどうするか 2

いつまでも勉強している訳にもいかないので、我々としてのLINQの評価をしなければいけません。

結論からいえば、LINQの採用は最小限にすることにしました。

理由は、LINQはDBへの問い合わせあるいは更新等(CRUD)については、だいぶ機能がそろっていると思いますが、これらのデータの表示については柔軟性に欠けると判断したからです。

LINQのサンプルとしては読み込んだデータをDataBindでコントロールに表示する例が載っています。しかし私たちはDataBindingを採用していません。ADO.NETの最初期に私たちも一度この採用を検討したのですが、おそらくバグと思われる異常な動きをするため使うのを断念しました。

そのためDBから得た情報をコントロールに表示するとき、すべてFormatし、逆に画面データをDBに書き込むときにはすべてParseしてからDBに書き込んでいます。LINQは遅延読み込みをしているのも一因だとおもいますが、LINQでよみこんだデータを効率よく体系的に(私たちのソフト資産を生かして)FormatなりParseなりをする方法を考えつきませんでした。

また、私たちは米FarPoint社のSpreadを多用していますが、FarPoint社のLINQ DataBindの対応がイマイチなのも理由の一つです。

これらの理由から私たちはLINQを全面的に採用するには時期尚早と結論しました。

便利に使えるところは使いますが、全面的には使わないことにいたしました。