DataSetについて

けちょんけちょんに言ってるとか言ってないとかで言えば言ってるので、遅まきながらその理由などをつらつらと。正直なところDataSetなんて現代の観点から使ってみれば、一発でどれだけクソなのか自明だろう、ぐらいに思ってたので別に言うまでもないと思ってたので特に述べてなかったのですが、意外と支持の声も大きいのですね。困惑するぐらいです。

DataSetというと型付きと型無しがありますが、形無しのほうは、もういらないんじゃないかな。カジュアルな用途ならExpandoObjectを使ってくれという感じだし、そうでないなら、C#で型無しのヘヴィな入れ物とか利点を損ねるしかないわけで。せめてdynamicに合わせた作り直しが必要よね。

それでもADO.NETと密接に結びついていて、たとえばSqlBulkCopyはDataTableしか受け取らないなどがある。だから必要か、というと、そうじゃあなくて。そうじゃなくて、それは害悪なんだって。そのせいでストリームで流し込めないし。今時だったらIEnumerableに対応していて欲しいところだというのに(なお、専用のIDataReaderを手作りすればストリームで流し込めます)。腐った現状を肯定するんじゃなくて、どうあるべきなのかを認識しよう。

ちなみにLINQ to DataSetは型無しDataSetのためのキャスト要因でしかないので、ほとんど名前だけでドーデモイイ代物です。型付きDataSetのほうは一応IEnumerable<TRow>なので不要なんですよね。

さて、話の主題のStrongly Typed(笑) DataSetのほうは、死んでほしい。今すぐに跡形もなく消え去ってほしい。なんでそうも恨み言が多いのかと言ったら仕事で割とヘヴィに使い倒しているから、なのですけれど。

Nullableに非対応

分かりやすく最大の馬鹿げた点はここですね。マトモな神経ならどれだけ頭可笑しいのか分かるはずで。作られた年代が年代だからしょうがない?いや、今話しているのは現代のことで、そんなNullable非対応のまま更新されず、大昔に見捨てられた代物なんてどんな選ぶ理由あって?

なお、型付きDataSetを知らない人に説明すると、nullが入る可能性のある列に対してはIsHogeNullというメソッドが生成されているので、そちらで事前チェックすればいい、というシステムになっています。if(row.IsHogeNull()) row.Hoge; といった感じ。もしnullの状態でrow.Hogeにアクセスすると実行時例外。

これ、すごく気持ち良くないんですよね。型付き言語の良さって型がドキュメントなことであり、C#の良さってそれがIntelliSenseでコードを書いている最中からリアルタイムに立ち上がって教えてくれるところであって。なんでコード書いてIntelliSenseも出ているのに、それがnullが混じる可能性があるのかないのか分からないの?Hogeの型がNullableならば、そこから伝わるのに。こういうC#の利点を損なうような代物は全力で許さない。

Enumに半分非対応

データベースの数値とC#上のEnumを関連付けることは割とあるシチュエーションだと思うわけですが(EntityFrameworkでもずっと要望に上がっていて最近やっとようやく対応しましたね……)DataTableもプロパティに関してはDBの型ではなくEnumに変更できます。ただし、TableAdapterによるメソッドの引数のほうは変えられないんですねー、あははぁ、intだー、intだぁー、凄いね、キャストだね。クソが。

ただたんにキャストすればいいだけだから大したことないぢゃん、と思うかもですが、これは非常に大きなことなのです。タイプセーフ、というだけじゃなくて、引数の型がEnumだと、それに沿うようIntelliSenseの第一候補として優先的に表れてくれて、こういう些細な気配りがC#の気持ちのよいプログラミングを支えているのです。

これでどこがTypedなのか。ありえないレベル。

使えないデザイナ

デザイナ、重いんだよね、普通に。激しくストレスなぐらいに。そして位置の設定はすぐに吹き飛んで横一列に並びきった整列へ。重い状態でセーブするとDesginer1.cs, Designer2.csと数字が延々とインクリメント。そして、長大奇怪なXMLに保存されるのでコンフリクトが発生したらマージ不能。OK、DataSetは古の悪名高きVisual SourceShredder(ロック方式なのでコンフリクトは原理上一応発生しない)とセットで使うべきものなんだな、それならばしかたがない。つまり、現代で使うべきものではない。

そして、基本的にクエリはこのデザイナから書かせるものなのですが、うまくSQLを解釈してくれない。ちょっと凝ったクエリを書くだけで、機能しなくなる。例えばSQL Serverの共通テーブル式とかうまく作れない。生SQLを書かせるのに、シンプルなSQLしか書けない。whereのin句にパラメータを並べるとかもできない。それなら逐語的文字列で書かせてもらったほうが百億倍マシだわ。というか書かせろという感じですが。(できなくもないですけれどね、ただもうそれならそもそもDataSet使わなくていいぢゃん、ほかの余計な制約もあるのだから、といったところで)。

お節介DataRowView

私の今の主戦場はWebFormsなのですが、RepeaterにDataTableをバインドすると、あら不思議、DataRowがDataRowViewに化ける!わー、嬉しいー、死ね。余計なおせっかいとしか言いようがない。これ、まあ現代的なC#erならばDataTableをLINQ使って加工したのをバインドしたりもするわけで、IEnumerable<DataRow>の場合は、そのままのDataRowが来る。ええ、同じはずの型が、違う型でやってくるなんて、悪夢すぎる。狂ってる。

文字列クエリ

Selectメソッド!紛らわしいですが、DataTableのSelectはLINQにおけるWhereにあたります。「文字列」でクエリ書かせるものが存在します。おお、文字列、タイプセーフじゃあないねえ……。型付きDataTableであっても戻り値は型無しDataTable、なんだねえ……。すごい、すごいすごい。いらないね。現代的に強化するならExpressionに対応させてタイプセーフなクエリを発行するとか、やりようはあるはずですが2005年で更新止まってるのでそんな高尚な機能が追加されることは未来永劫ないでしょう。

おまけに型付きのDataTableはLINQ to Objectsで扱えるので、素直にLINQ to Objectsにまかせてしまったほうが遥かに良い。LINQ以前は、DataTableってインメモリDBとしてある程度のクエリが簡単に実装できる、というところがあったのですが、LINQ以後の世界では純粋なC#コードとして簡単にソートも射影もフィルタリングも可能、それどころか備え付きのクエリとは比較にならないほど柔軟で強力なクエリ能力を手にしているので、もはや中途半端なインメモリDBは不要で、純粋なコレクションだけで構わないぐらいなのですよね。

モック作るのが面倒くさい

専用のヘルパでも作りこまない限りは絶望的。

じゃあどうするの?

そうですね、ここの回答がない限りはDataSetから抜けられないのですしね。私としてはLINQ to SQLでいいぢゃん(EntityFrameworkじゃなくてね)、と思うのですけれど。MSのコンサルタント連中が2009年末にもなっていま使うべき、学ぶべき.NETテクノロジはどれ?という講演で「まずはデータセットやテーブルアダプタを活用できることが大事、とか」「更新系が弱い」とか言い続けているのが絶望的。なんでDataSetが基礎知識なんだよ、馬鹿じゃねーの。

オールドテクノロジーで縛り付けたいのかしらね。求められるのは、ある程度の弱さを知覚した上でのPOCO+DataContextでの使いこなしかたの説明が求めるわけで。まさか、2012年の現在でもEntityFrameworkは更新に弱くてDataSetがまずは基本ですね、とか言っていやあしないですよね、知らないけど。

何でも得手不得手があって使い分けが大事、とかいうのはすごく簡単な逃げ口上ですが、何にでもメリットデメリット、そして未来の潮流を踏まえたうえでの学習の投資で天秤にかけなければならない。DataSetに未来はどこにあるの?腐臭を放ってる資産の保守ぐらいでしょ。こういう影響力ある人らがどうしょうもないことを言うのには、猛烈に腹が立っていてずっと不信感しか持てない。今のところ最後の赤間本であるLINQ本も急いで作った感バリバリでとてもひどいしね(そのことが前説にも書いてあるしね!影響力があるのは分かっているのでしょうから、もう少し丁寧に書けなかったものなのか)。

まあ、WebFormsやWinFormsにはDataSetを前提においたコントロール資産が山のようにあるから……。というのは移れない理由にはなるでしょうね。その場合はプラットフォームごとサヨウナラするしかないんじゃないの?そこまでは知りませんよ。で、その完全に縛られたポトペタ成果物って、魅力的なの?公に出たときに競争力あるの?年々、競争力を失っていっていると思うんですよね。それが許される賞味期限はとうに過ぎていて、残っているのはガラクタだけ。

そして、これからは定型的な業務アプリへならLightSwitchも出てきましたしね(VS2012からは標準搭載で、出力先もSilverlightだけじゃなくHTML5が選べるので実用性高くなったと思う)

じゃあEF使えばいいの?

LINQ to SQLは更新されていなくて、今のMSが推してるデータアクセステクノロジはEntityFrameworkだからEF使おう、というと、うーん、私はEntityFrameworkあんま好きくないので、そんなに薦めないかなあ、とか言っちゃったりして。EntityFrameworkの思想に一ミリも魅力を感じないので。LINQ to SQLのほうがまだずっといいよ!更新されてないぢゃん、というならDataSetだって一緒だしさ!なんというか、DataSetといいEFといい、ADO.NETチームってとってもセンス悪いんじゃないか、と思ったり。(ちなみにLINQ to SQLはC#チーム側からの実装だそうで、さもありなん)。あと同じくセンス悪いなーって思うのはEnterprise Libraryとかですね!

ORMは信用ならねえがDataSetはクソだから、もはや生ADO.NETで、つまりDbConnectionからDbCommandでDbReaderで、というので手作業しかねえ!というのはあると思いますが、うーん、手作りはナシね、ナシ。生を生のまま扱うのはアレなので、ちょっとしたユーティリティ、独自マッパーっぽいものは作ると思うのですが、これがねえ。私は以前に、センスのない独自マッパーを使わされていたことがあったのですが、使いにくくて結構な不幸でした。

単純にマッピングする薄い代物だとはいえ、作るにはそれなりなセンスと技量が必要なのです。で、そういうのをMicro-ORMと称しています。生ADO.NETのちょこっとだけ上層にあって主にクエリ結果のマッピングを効率よく行う、程度な代物なので、実質的には生ADO.NETを扱ってると考えてもいいです。現在だと代表的なものにdapperとか、色々と良いものがあるので、それらを選べばいいんじゃないですか。

フルORMにしたって、Microsoft純正以外にもLightSpeedとか良い選択肢がありますよ。NHibernateはどうかと思いますが。

ORMについてはLightSpeedの作者の語るORMのパフォーマンス最適化という記事が良いと思います。特にDataSetからの移行を意識するのならば。LINQ to SQLの成り立ちについてはThe Origin of LINQ to SQL を訳してみた - NyaRuRuの日記を。

Micro-ORMによるデータコンテキスト

Micro-ORMは、当然ながらDataSetやORMが持つ作業単位の保持はないので、そういうのが必要だったら、ある程度は手作業で作りこむ必要はあります。

少し実例を挙げると私が作っているというか作ったものは、データ保存先がDBだけじゃなくてMemcached(キャッシュとしてだけじゃなくデータ保持にも使う)だったりRedis(ListやHashなどのデータ構造を持つKVS)だったりが、それぞれのパフォーマンス的に適していると思える箇所に挟み込まれたデータコンテキストをなしていて、一個のDBだけの世界を構築するORM系はどれも不適切でして。

かといってDapperなどの既存のMicro-ORMも若干、某弊社の事情に合わないところがあるので、自分で作ろうかなあ(上で作るな、と言ってたのに!)とはずっと思ってるところですね。ベースになるMicro-ORMは既にある→DbExecutor - Simple and Lightweight Database Executorのと、拡張のアイディアは沢山あるので、あとは実装時間ががが。

まとめ

DataSetは単純に言って古い。言語機能が年々強化されていく中で、2005年の時点でストップしている(しかも2005の時点の言語機能(Nullable)にすら非対応)なものを使うのは、プログラミングにおいて足枷でしかない。7年前ですよ、7年前。あんまり一般化して言うのもアレですが、ドトネトの人って浦島太郎な雰囲気ありますよ、キャッチアップが遅すぎるというか枯れてるのが、とかかんとかって。エンタープライズだとどうだとか業務アプリだとどうだとかメンバーのレベルがどうだとか、そんな言い訳ばかりで、すごく格好悪い。

すっごくクールじゃないわけですよ。そんな言説が目立つところに、魅力を感じるのは難しい。せっかくC#や.NETは魅力的なのに。というわけで、私としては、資産がどうだとかこうだとかって言説は吐きたくないし、もっと活力ある感じになればいいな、って思います。2009年の現実に最も使える.NETのバージョンはどれ?→.NET 2.0が現時点でベスト、とか凄く絶望的じゃないですか。まあ、えんたーぷらいずの世界ではそれだししょうがないというのならそうなのでしょうが、なるべくそうじゃない世界を作りたい。

そのためにも、新しく、負の遺産を作るのだけはナシです。DataSetに別れを。

Profile

Yoshifumi Kawai

Cysharp, Inc
CEO/CTO

Microsoft MVP for Developer Technologies(C#)
April 2011
|
July 2024

Twitter:@neuecc GitHub:neuecc

Archive