C#でORM

ここ数ヶ月、今までのTclやRubyとほぼ完全に離れて、C#Windowsアプリケーションを作っている。

そのかなりの時間を費やしたのが、Entity Frameworkというやつだ。
今までWebアプリではRailsActiveRecordを使って、WindowsアプリではXOTcl版のActiveRecordでやってきたので、いわゆるC系やJavaプログラマが標準的に使うデータベースアクセスの方法をほとんど知らなかった。

それで、O/Rマッパーを探したのだが、もうこの世界はゴミの塊のようなライブラリが乱立している。そしてオープンソースのライブラリは何年もメンテナンスされてないものばかり。フリーで完成度の高そうなのはNHibernateくらいだけど、XMLによるマッピングが必要なので却下。

コードジェネレータ付きのやつはあるけど、クラスへのマッピングが不要なのは基本的に存在しない。

Gentle.NET
http://sourceforge.net/projects/gopf

Fluent NHibernate
http://fluentnhibernate.org/

Opf3
http://www.opf3.com/Opf3/

結局、外部のものを使うよりは、Visual Studioが提供するものをつかったほうがよいという結論に至り、DataSetやらLINQ to SQLやらLINQ to Entitiesやらを検討した。どうやらMicrosoftはEntity Frameworkがイチオシということのようだったので、それにしてみたが、もう最悪な日々の連続だった。それでも、C#を礼賛している人々が多いという事実に、そこには何か根拠があるに違いないと思って我慢して、MSDNをはじめとする、たくさんの文献と、スクリーンキャストを参考にしたり、実用性の無いサンプルコードをダウンロードしては、クソ重たいVisual Studio 2008をいちいち立ち上げて、勉強したのだ。

その甲斐あって、ようやくCRUDとアソシエーションを使った作業をほぼまともにできるようになってきた。
そろそろ、ActiveRecordでいうところの、validationやbefore_saveみたいなイベントハンドラに手を付けようとしている。
これも可能ということだが、まあ、ぜんぜん簡単ではないし、無駄にキャストが必要な気がする。

昨日はしばらくVisual Studioを立ち上げていたせいか、カラム追加をEDMに同期させようとしたところ全てが吹っ飛んだのだが、Subversionのおかげで助かった。

ものすごく苦労してできた結果、当たり前のことがようやくできただけだというのに、なんとなく満足してしまう自分がいる。
しかし、仕事は進んでない。

たしかに、こんな複雑なシステムを作って、販売できるMicrosoftの力はすごいと思う。でもいつか まつもとゆきひろさんが、「複雑さを統合開発環境で補完するのは間違いだと思う」、という意味のことを言っていた。いまではその言葉は正しいと身をもって感じる。

早くこんなものを礼賛するのをやめて、C#上でRubyが動くようになることを期待する。Silverlight3ではデスクトップアプリの作成も可能になるらしく、その際Rubyも使えるとのうわさ。それが実現すれば、即刻こんな壮大でクソみたいな仕組みは不要になるはずだから。IronRubyはいつの日か完成を見るのだろうか。。。あまり期待しないほうがよさそうだが。適当なところで妥協して、偽Rubyを作られて中途半端に普及されても困るし。JScriptみたいに。

ちなみに今回難儀したのはEntity Frameworkを使ったせいだけじゃなく、SQLiteを使ったためでもあると思う。ADO.NET 2.0 Provider for SQLiteというフリーのライブラリがあるのだが、これはLINQ to SQLをスキップしてEntity Frameworkに対応してしまったものだが、LINQ to Entityを使った場合にTransactionScopeを使うと自分自身をロックしてしまいSaveChangesがタイムアウトするというバグがある。いや、断言する程よく知らんから、たぶんバグだと思うくらいにしておこう。とにかく、ActiveRecordに比べるともう死にたくなるほどしんどいということだ。

その挙句トランザクションも使えないという。SQLiteトランザクションが使えないということがどれだけ致命的なことか。あ、でもこれはMicrosoftのせいじゃないな。つい言い過ぎた。

たぶん次期バージョンでも魅力的な進化はないだろう。新機能や改善点の分量ではなく、そもそも方向性が違うので。

ADO.NET 2.0 Provider for SQLite (System.Data.SQLite) (パブリックドメイン)
http://sqlite.phxsoftware.com/

dotConnect for SQLite (こっちは商用)
http://www.devart.com/dotconnect/sqlite/

Entity Framework (Entity DesignerはVisual C# Express Editionでも付いてくる)
http://www.atmarkit.co.jp/fdotnet/special/vs2008sp1ef/vs2008sp1ef_01.html

LightSpeed (EFより更新頻度が高いことが売りらしい)
http://www.mindscape.co.nz/Products/LightSpeed/

SQLite3にmigrationでadd_indexしても速くならない

Railsのmigrationで、add_indexというのがあります。
これをするとインデックスが作成されるので速くなるということで、こんなことをしていました。

class AddIndexToCount < ActiveRecord::Migration
  def self.up
    add_index  :counts,  :column1
    add_index  :counts,  :column2
    add_index  :counts,  :column3
  end

  def self.down
    remove_index :counts, :column1
    remove_index :counts, :column2
    remove_index :counts, :column3
  end
end
CREATE INDEX "index_counts_on_column1" ON counts ("column1")
CREATE INDEX "index_counts_on_column2" ON counts ("column2")
CREATE INDEX "index_counts_on_column3" ON counts ("column3")

使い方くらい調べないといけないですよねぇ。これでは全く高速化されない。

TkSQLiteの機能を使ってインデックスを追加すると、以下のようなSQLが実行され、500ms->3msと100倍以上高速になりました。

CREATE INDEX 'counts_idx' ON 'counts' ('column1', 'column2', 'column3')

migrationでこのようなインデックスを作成するには、以下のようにします。

class AddIndexToCount < ActiveRecord::Migration
  def self.up
    add_index :counts, [:column1, :column2, :column3], :name=>:counts_idx
  end
  
  def self.down
    remove_index :counts, :name=>:counts_idx
  end
end

はあ、今までのデータベース全部更新しなくては。

Castle.ActiveRecordはNHibernate(LGPL)に依存しているので、使えない?

とおもったら、NHibernateの作者はLGPLに関する解釈についてコメントしている。
http://hibernate.org/356.html

Hence our interpretation of the LGPL is that the use of the unmodified Hibernate source does not affect the license of your application code.

NHibernateの作者は改変しない限り本体のライセンスに影響ない。つまり、商用製品のソースコード公開しないでも使っていいよと解釈できる。作者がいいって言ってる以上、いいんじゃないだろうかと思うが、興味があったので、もう少し突っ込んでみる。

NHibernateと同様の解釈をしている人は他にも見られる。
http://stackoverflow.com/questions/94346/can-i-legally-incorporating-gpl-lgpl-open-sourced-software-in-a-proprietary-cl

NECOSSライセンス・コンプライアンス コンサルティング・サービスの資料を見るとLGPLで配布されているライブラリを利用するプログラムは、そのリバースエンジニアリングを許可しなければならないとある。
OSSライセンス・コンプライアンス コンサルティング・サービス: OSS/Linuxソリューション | NEC
「LGPLライブラリを改変,商用製品と配布したい」(1) Linux Square − @IT
http://oooug.jp/start/open/open04.html

これらの解釈はLGPLの意図するところと矛盾しないのだろうか?LGPL2.1の条文の最後の方を見る限り作者の許可を求めるなどで、ある程度の融通を効かしているようにも思える。

LGPLのはじめにのところを見ると、本体のソースを開示せずにフリーのライブラリを使うことの制限を緩和することを目的としているように思われるのだが、途中のところの条文を見ると、それは駄目みたいなことが書いてあって言いたいことを読み取るのが難しい。一般的には本体のリバースエンジニアリングを禁止しなければOKという見方が多いようだ。

そういうわけで、NHibernateを改変しないでリバースエンジニアリングを禁止しない商用製品とともに再頒布することは、LGPL違反ではないと結論づけたい。

ちなみにC#クロスプラットフォーム実装であるMonoはGPL

System.Data.SQLite(ADO.NET provider for the SQLite)

パブリックドメイン知的財産権すら主張していない。

Full Source Included. 100% Free.
The full source to the wrapper and SQLite engine is in the public domain.
There are zero licensing restrictions for private or commercial use.

Castle Project + System.Data.SQLite

C# on Rails + SQLite3をやろうとすると、今のところこれが有力と思われる。

C++のベテランプログラマーならばフリーのライブラリなどに頼らず、自力で何でも作るのかもしれないが、偽プログラマーにとっては自分で作るなんてもってのほかである。偽プログラマーに優しいOSSライセンスにはどんなものがあるのか調べてみる。

BLTが捨てられない

最近Tcl8.5について調べてて、いろんな点でかなり惹かれてます。ついでにTDK3.2もいろいろバグがあるので、TDK5にも乗り換えたい。

しかし、blt::graphに依存しているため、8.5に乗り換えることができないでいます。BLTはメンテナがいないのでActiveTclのパッケージにも入れてもらえない。

8.5がalpha版だった時は、いろいろな人が取り組んでいたようだけど、正式版が出るのに時間がかかってしまったので、みんなPythonRubyに行ってしまいました。

dqkit: dqsoftware - Browse /dqkit at SourceForge.net
A Stub-enabled BLT2.4z for Windows - mynote

TklibのPlotchartを使ってBLT並みのことをやるのはしんどそう。