Tags: 技術日記

技術日記
技術調査記録Edit

XCode4.2にアップデートしたら、今まで使えていたSubversionレポジトリにつながらなくなった。よくわからん。ひとまず後で。

ASP.NET MVC 3で作ったアプリケーションを、Windows 2003 R2で動かしてみる。

ひとまず普通にコンパイルしたアプリケーションディレクトリを、丸ごとサーバー機にコピーし、IISでアプリケーションとして(適当なディレクトリ下に)追加してみるが、動かない。どうやら必要なDLLがないようだ。

iis7 - IIS 7 can't run ASP.NET MVC application due to missing System.Web.Helpers - Server Faultにあるように、ASP.NET MVC 3で使われる、

  • System.Web.Helpers
  • System.Web.MVC
  • System.Web.WebPages
  • Microsoft.Web.Infrastructure
  • System.Web.Razor
  • System.Web.WebPages.Razor
  • System.Web.WebPages.Deployment
をローカルコピーするように設定する。参照として含まれていないものは参照として追加しておく。そうするとビルド時にbinディレクトリ内にコピーされる。

これで基本的なアプリケーション部分は動作する。つづいて、MySQLに接続したいんで、ADO.NET Driver for MySQL (Connector/NET)をダウンロード&インストールする。

これでひとまずASP.NET MVC 3で作成したWebアプリケーションの基本機能と、MySQL接続機能が動作する。

このアプリケーションをサーバーのルートディレクトリで動作させるために、デフォルトWebサイトのベースディレクトリをアプリケーションディレクトリに変更。これでひとまずサーバーにアクセスするとトップページ以下でASP.NET MVC 3アプリケーションが動作した。

続いて、デフォルト以外のアプリケーション設定値を取り扱う方法。といっても、まあ普通にWeb.Configに書けばいいんだよね。configuration/appSettings以下に適当なキーで設定値を追加する。たとえば、

[sourcecode language="xml"]
<?xml version="1.0" encoding="utf-8" ?>
...中略

...中略
 
    ...中略
    
  

[/sourcecode]
なんて感じでfooというキーでbarという値をセットした場合は、
[sourcecode language="c#"]
using System.Configuration;
..中略
string foo = (string)ConfigurationManager.AppSettings["foo"];
[/sourcecode]
なんて感じで取得できる。

続いてASP.NET MVC 3でバイナリファイルをダウンロードさせる方法。通常のコントローラのアクションではActionResult型を戻り値にしたりして、結びつけられたビューでのレンダリング結果を返したりするけれども、ファイルダウンロードならば特にActionResultとかいらない。

[sourcecode language="c#"]
...適当なコントローラクラスの中
public void Download(string filename)
{
  string localFilePath = ...; // ダウンロードしたいファイルのローカルパスを取得
  Response.ClearContext();
  Response.AddHeader("content-disposition", "attachement; filename=" + filename);
  Response.ContentType = "application/octet-stream";
  Response.WriteFile(localFilePath);
  Response.End();
}
[/sourcecode]
こんな感じで簡単にダウンロードできた。

ASP.NET MVCは裏で何をやっているのかよくわからないフレームワークだけど、最悪アクションメソッド内でRequest、Responseオブジェクトが見えているから、正しくアクションメソッドが呼び出されてくれたら、あとはRequestとResponseを使って、限りなくプリミティブなレベルでの処理を書けば、なんとかなるっぽいな。

Published At2011-11-09 21:42Updated At2011-11-09 21:42

技術日記
技術調査記録Edit

ASP.NET MVC 3で作成したアプリケーションをIISに手動で配置するにはどうすればいいんだ? Web発行ウィザードとかを使えば何とかなりそうなのはわかっているんだけど、そういうのを使わずに手動で配置できるようになっておかないと、何かトラブったときにどこをどう調べればいいのかわからなくなるから、まずは手動での配置の仕方を知っておきたい。

という調査をしようと思ったんだけど、ずっと放置していた件があるんでそっちを先に。iOS4の頃に作ったiPadアプリが、iOS5にしたら動かなくなった件。

MonoTouchを使うためにXcodeを3にしたり4にしたりいろいろいじったんで、開発環境の設定やライブラリ参照もだいぶ変わってしまっている可能性があるので、 ひとまずXcode4のiOS5対応最新版をダウンロード&インストール。テスト用のiPadをiOS5にアップデート。

プロファイルのアップデートとかいろいろやって、テスト機との接続環境を整えてから、プロジェクトをコンパイル&実行。と思ったらコンパイラの設定を変えろと言われる。 iOS 5 for Developers - Apple Developerに書いてある、

Automatic Reference Counting (ARC) for Objective-Cによって、メモリ管理をコンパイラの仕事にします。新しいApple LLVMコンパイラでARCを有効にすると、retainまたはreleaseを再度タイプする必要がなくなり、クラッシュやメモリリークを減らすと同時に、開発プロセスを飛躍的に簡素化します。コンパイラはオブジェクトを完全に理解し、もはや使われていない各オブジェクトを瞬時にリリースします。その結果,アプリケーションは、予測可能で滑らかな操作性を備えて、これまで以上に速く動作します。
のことか。従来方式で作っていたコードを、そのままApple LLVMコンパイラでコンパイルしてもいいのかな? ARCとやらは手動メモリ管理のコードもそのまま扱ってくれるのか?

さらに使っていたフォントArial Blackがなくなったとか言われる。でもなんかおかしいな。ios5 - Cannot apply some font as custom font on xcode 4.2 for develop iOS 5 application - Stack Overflowと同じ症状か。

Applications that want to use custom fonts can now include those fonts in their application bundle and register those fonts with the system by including the UIAppFonts key in their Info.plist file. The value of this key is an array of strings identifying the font files in the application’s bundle. When the system sees the key, it loads the specified fonts and makes them available to the application.
でも、これってiOS5になったからどうこうって話じゃないはずなんだけど。まあどうでもいい部分でしか使っていなかったから、ここは深追いしないでシステムフォントに変更することにする。 で、デバッグ実行してみたところ、

[sourcecode language="c"] warning: check_safe_call: could not restore current frame warning: Unable to restore previously selected frame. [/sourcecode]

とか出ている。

ググると、なんかプロジェクトをコピーしてコンパイルしなおせば直る、とかおまじない的な対処方法とか書かれていていやだなー。実際そういうこともたまにあるんだけどさ。

で、デバッグモードでコードを追っていったら、UIWebViewのsetScrollingEnabledを呼んでいるところでこけていた。これ非公式APIだったけど、iOS5では通らなくなったのか。しょうがないんで使うのをやめる。

それでひとまずは起動するようになったけど、今度UISwitchの表示がおかしくなったり、設定画面で終了ボタンを押しても元の画面に戻らなくなったり。

UISwitchの表示がおかしいのは、iOS5のUISwitchを日本語で使うと・・・:ゲームとかプログラムとかコーギーとか:So-netブログが原因だね。全部のxibファイルのLocalizationにJapaneseを追加。やってみるとわかるけど、XCode 4.2のその辺の操作性が軽くバグってる。実害はないけど。

終了ボタンで元の画面に戻らないのは、Dismiss modal view in iOS5 sdkが原因だった。モーダル表示したビューコントローラーから前の画面に戻るときに、従来は、

[sourcecode language="c++"] [self.parentViewController dismissModalViewControllerAnimated:NO]; [/sourcecode]

でいけたんだけど、iOS5からは、

[sourcecode language="c++"] [self.presentingViewController dismissModalViewControllerAnimated:NO]; [/sourcecode]

じゃなきゃだめになったようだ。

これでだいぶ動くようになったんだけど、まだ動かないコードがある。

モーダル表示されたビューコントローラから、呼び出し元のビューコントローラをself.parentViewControllerで解決しつつ、そのメソッドを呼ぶ処理を書いていたんだけど、どうやらself.parentViewControllerは呼び出し元のビューコントローラじゃなくなったらしく、そのメソッドが呼ばれてくれない。

これもさっきのモーダルビューを閉じるときのコードと同じく、parentViewControllerではなくpresentingViewControllerを使うと動く。これは結局公式にはどういう扱いなのかとヘルプドキュメントを読んでみたら、

Prior to iOS 5.0, if a view did not have a parent view controller and was being presented modally, the view controller that was presenting it would be returned. This is no longer the case. You can get the presenting view controller using the presentingViewController property.
iOS5以前ではモーダル表示されたビューがparentViewControllerを持たない場合は、parentViewControllerで呼び出し元のビューコントローラが取得できたけど、iOS5以降ではそうならないから、呼び出し元が欲しければpresentingViewControllerの方を使えって話なのね。

そう言われてみると、ビューの親子関係って本来はaddSubViewした場合に発生するから、モーダルビューと呼び出し元は親子関係じゃない。ただ、意味合い的には親子関係っぽいから、なんとなくparentViewControllerで呼び出せるようにしていた。でも、もうそれはやめて親ではなく、呼び出し元(presenting)として明示的に取得してね。ということなんだろう。確かに元々の仕様はあまり美しくないけど、今更こんなでかい仕様変更しなくてもいいのに。

しかも、この仕様変更はバージョン間の非互換性を自前のコードで埋めなければならないようで、OSバージョンとかpresentingViewControllerプロパティの有無とかを見ながら、どちらを使うか意識した実装が必要らしい。いっそUIViewControllerを自前で拡張して、modalParentViewControllerとかいうプロパティを追加するように書いた方がましかもな。Objective-Cで既存のクラスを外付けで拡張する書き方ってどんなんだっけ。

ひとまずiOS5にアップデートしたiPadではだいたい動くようになったけど、今度は以前は大量にコンテンツをロードした状態で動作させてもちゃんと動いていたのに、ある程度以上コンテンツをロードした状態で実行しようとするとアプリが落ちるようになっている。なんじゃこりゃ。

軽くデバッガーで追ってみたけど、UIWebViewとかUIImageViewとかにデータをロードしている途中で落ちたり落ちなかったりといった感じで、簡単には追求できなそうだったんで、いったん追求終了。

Published At2011-11-08 19:09Updated At2011-11-08 19:09

技術日記
ASP.NET MVCで環境依存の設定Edit

よくあるproduction、staging、development的な環境依存の設定をASP.NETではどう書くの?という話。

Visual Studio 2010のソリューションエクスプローラーからWeb.configを見てみると、Web.Debug.configとWeb.Release.configがぶら下がって見えるんで、どうやらそんな感じで環境依存の設定をかけるっぽいね。で、具体的にどうやって書くんだろう?

Web アプリケーション プロジェクト配置の Web.config 変換構文

がその肝らしいな。.NET Framework 4って書いてあるから、これってVisual Studio 2010以降に追加された機能なのかな? それ以前はどうやっていたんだろう?

ともかく肝としては、

Locator 属性で、なんらかの方法で変更する Web.config の 1 つまたは一連の要素を指定します。 Transform 属性で、Locator 属性によって見つけられた要素に対し実行する操作を指定します。
ということらしい。仕様をまとめると、
  • 記述されたノード+xdt:Locatorという属性によって、設定値が置き換えられるターゲットを指定する
    • Condition(XPath expression)で、カレントノードからの相対XPath指定
    • Match(attrname)でカレントノード以下のノードで、指定された属性名(attrname)にマッチ(完全一致)するターゲットを指定。属性名はカンマ区切りで列挙可能
    • XPath(XPath expression)で、絶対XPath指定
    • Locatorが省略された場合は、そのノード自体が指定されたことになる
  • xdf:Transformという属性で、設定の置き換え方法を指定する
    • Replaceで単純置き換え。複数のターゲットにマッチした場合は最初の一つだけ置き換え
    • Insertで兄弟ノードとして末尾に追加
    • InsertBeforeで指定要素の直前に追加
    • InsertAfterで指定要素の直後に追加
    • Removeで指定要素を削除。複数のターゲットにマッチした場合は最初の一つだけ削除
    • RemoveAllですべての指定要素を削除
    • RemoveAttributesで指定した属性を削除。属性はカンマ区切りで複数指定可能
    • SetAttributesで指定した属性値を設定。
って感じ。

単純に環境ごとに違うDB接続設定を使いたいような場合は、環境ごとのDB接続設定をそれぞれ記述して、xdt:Transform="Replace"にしておけば丸ごと変更される。環境ごとにソフトウェアロードバランスするDBを追加したい場合なんかは、Insertで追加したりするんだろう。

具体的に別の環境設定を追加したい場合は、「構成マネージャー」から新しい環境を追加し、さらにWeb.configから「構成変換の追加」を実行すると、Web.[新しい構成名].configファイルが追加される。

ということで、試しにProductionという構成を追加して、Web.Production.configにDB接続先の設定変更を行い、Production設定でVisual Studioからビルド&実行してみたんだけど、特に何も変わらない。どゆこと?

試しに最初からあるDebugとかReleaseとかを書き換えてみたが、それでも特に変わっている様子がない。いろいろ試行錯誤した結果、このWeb.configの書き換えはVisual Studioからビルド&実行したときには行われないようだ。

「Webの発行」から適当なディレクトリに発行を行ってみたところ、ちゃんとWeb.Debug.configで書き換えた設定が反映された。でも、自前で追加したWeb.Production.configに関しては、Productionビルドして発行する設定を行っても、特に設定変更が反映されない。

方法: Web.confg の変換を無効にする」にある設定変更を反映させない方法のどれかが有効になっているんじゃないかと思ったけど、特にどれも問題がなかった。これ、自前で追加したビルド構成の設定変更を反映させるにはどうすればいいんだ?

と疑問に思うが、ひとまず目先はDebug、Releaseの二つの設定変更が有効に働いてくれれば問題がないので、これ以上の深追いはやめる。こんなしょうもないことを調べるのにもずいぶん時間がかかっているし。

Published At2011-11-07 21:07Updated At2011-11-07 21:07

技術日記
WordPress Plugin Twitter Toolsで記事更新時に本文もTwitterに送りたいEdit

ここのWordPressでTwitter ToolsというTwitter連携用プラグインを使っている。

記事を投稿したときに自動的にそのことをTwitterに投稿する機能があるんだけど、これは記事名+URLだけしかツイートとして送ってくれない。いちいち記事タイトルつけるのが面倒くさいから、記事タイトル=カテゴリー名で運用しているとこれじゃーどんな記事なのかさっぱりわからない。

というわけで、適当にソースを見ていじってみた。WordPressの管理ツールでプラグインのソース編集からtwitter-tools/twitter-tools.phpを選び、適当にそれっぽいところを変更してみる。539行目辺りに、

[sourcecode language="php"] $tweet->tw_text = sprintf(__($this->tweet_format, 'twitter-tools'), @html_entity_decode($post->post_title, ENT_COMPAT, 'UTF-8'), $url); $content = preg_replace('/\s+/m', ' ', html_entity_decode(strip_tags($post->post_content), ENT_COMPAT, 'UTF-8')); $tweet->tw_text .= ' / ' .$content; $tweet->tw_text = mb_substr($tweet->tw_text, 0, 136, 'utf8') . '...'; [/sourcecode]

って感じで追加。この記事を投稿したらTwitterに本文概要が送られたら成功。管理ツールから適当に修正したプラグインが一発で動くか! 奇跡を信じて!

うーん、更新されない。Twitterへの投稿自体がうまくいっていないから、根本的に動いていないっぽいな。これプラグインの動作ログを管理ツールから確認できたりしないのかな?

よくわからないが、投稿するツイートを120文字+"..."に変更したら動いたっぽい。文字数の問題だった? まあいいや。

ああ、わかった。mb_strcutの第4引数でエンコーディングを指定していなかったから、mb_strcutが正しく動作していなかったっぽい。たぶんこれでちゃんと動くだろう。

追記@2012/01/27)この記事を検索してくる人がいるんで、追記。Twitterの文字数カウントはバイト数じゃなくて文字数だから、mb_strcutじゃなくて、mb_substrの方だった。ということで上記ソースコードは修正してある。mb_strcutだと投稿される本文の抜粋の量がものすごく少なくなるので注意。

Published At2011-11-07 18:00Updated At2011-11-07 18:00

技術日記
技術調査記録Edit

結局DBレイヤーはADO.NET Entity Frameworkで作ることに決めたのだが、今までいろいろいじってきたプロトタイププロジェクトは、いろいろなDBレイヤー技術を試しすぎて汚いコードになってしまったので、もう一度新規プロジェクトから作り直すことにする。

で、新規ASP.NET MVCプロジェクトを作ろうと思ったのだが、前回はまだVisual Studio 2008だったのでASP.NET MVC 2を選択したのだが、試している間にVisual Studio 2010にアップデートしたので、ASP.NET MVC 3が選べるようになっていた。 2のままにしておいた方がMono環境との互換性が高いかなーとか思ったりもしたのだが、ただでさえややこしいのに、Mono環境との互換性まで考えていたら破綻しそうだから、3で行くことにする。 が、そのプロジェクト作成ウィザードではビューエンジンとしてaspxかRazorかを選択できたり、HTML5セマンティックマークアップを使用するかどうか選択できたり、なんか知らない機能が増えていた。しょうがないんで、ASP.NET MVC 3について学習してみる。

颯爽登場!ASP.NET MVC 3の概要を押さえる(1/4):CodeZine

上記リンクは主にASP.NET MVC 2からの変更点を踏まえての概要紹介。

“Razor”の紹介 - ASP.NET向け新ビュー・エンジン - @IT

ビューエンジンRazorについて。従来のaspxよりは書きやすそうなので採用する方向で。

Published At2011-11-06 14:30Updated At2011-11-06 14:30

技術日記
技術調査記録Edit

dblinq2007 - LINQ provider for Oracle, PostgreSQL, MySQL, Ingres, SQLite, Firebird and ... SQL Server (C# 3.0) - Google Project Hosting

Entity Frameworkを使わないとなると、LINQ to SQLが次の候補になるのかな。Visual Studioから新規データクラスの追加でLINQ to SQLクラスは一応選択できるけれども、サポートされていないProviderってことで、結局標準状態ではまともにMySQLは扱えない模様。

しょうがないんでググってみたら、上記のDBLinqというものが見つかった。様々なRDB用のLINQプロバイダークラスを開発しているオープンソースプロジェクトらしい。ただ更新履歴を見ると2010年4月くらいまででほぼ開発は止まっているみたいだけど。

使い方としては、コマンドラインツールDbMetal.exeにオプションとしてDB接続方法を指定して実行すると、そのDB接続用のLINQ向け.dbmlファイルを生成してくれるんで、それをプロジェクトに追加して使用する。

ただし、標準で生成される.dbmlファイルはそのままじゃ使えない。まあ大して大きな問題ではなく、使用するProviderクラス名を手動で直したり、GetTableの戻り値のクラス名をDbLinqのものに変更したりといった程度なんだけど、LINQで使いやすいようにDB定義をいろいろ修正してから生成し直すたびに、同じことを手動でやらなきゃいけない。あとこういう状況のまま放置されているってことは、実際に使われている事例があんまりなさそうだよね、と思うとモチベーションがだだ下がる。

ちょっとこれじゃーなーと思って、今度はプリミティブにMySql.Data.MySqlClient.MySqlConnectionから地道にSQL文を書いてDB処理を書く方法も試してみたりもしたけれど、これはやっぱり今更やりたくないな。System.Data.DataSetExtensionsとか使ってDataSetをEnumerableにしてみたりもしたけど、そこまでやるんだったら素直にADO.NET Entity Frameworkの範囲内で試行錯誤した方がましな気がしてきた。

というわけで、一周回ってもう一度振り出しに戻ってみることにする。

Published At2011-11-02 16:12Updated At2011-11-02 16:12

技術日記
技術調査記録Edit

.NETの新データアクセス・テクノロジ「ADO.NET Entity Framework」 - @IT

ADO.NET Entity Frameworkのお勉強の続き。ASP.NET MVCを使うつもりなので、ASP.NETを使うフロント側の情報は参考にならないなー。

EDM(Entity Data Model = Entiry Frameworkで生成するデータアクセスモデル)でクエリを発行する3つの方法

  • Entity SQL + Entity Client
  • Query Builder(Object SQL) + Object Services
  • LINQ to Entities + Object Services
Entity SQLってのが一番低レベルなDBラッパーらしいけれども、Entity Framework専用クラスになっている辺りがいやらしいな。EntityClientとSqlClientは相似なクラスとして、
  • アクセス対象 DBサーバー自体 → EDM
  • データ接続クラス SqlConnection → EntityConnection
  • SQLコマンドクラス SqlCommand → EntityCommand
  • データリーダークラス SqlDataReader → EntityDataReader
という関係のようだ。ただ、機能的にはEDM向けに拡張されているらしい。ただし、Entity SQLではSELECTしかサポートしてないんだと。INSERT、UPDATE、DELETEしたい場合はどうするんだろう? SqlClientを使うの?

しかも、Entity SQL/Query Builderで利用できるステートメントという表とその後の説明を読むと、ここで書けるSQL文ってのは、RDBに直接渡されるものではなく、Entity Frameworkの実行エンジン内にあるSQLパーサーで実行されるものってことか。

EDM向けのSQL文をEntityClientで発行すると、それがEDMを通して実際のRDB向けSQL文に変換されて実行されるというイメージなのね。うわー、なんか気色悪いなー。

Object Builderってのは、上記のEntity SQLをクラスライブラリ上にラッピングしたものね。サンプルコードを見ると、文字列とLINQライクなメソッドが混ざり合ってて、気色悪いコード表現になるなー。すげー使いたくない。

ただ、この方法でオブジェクトを操作して、SaveChangesメソッドを呼び出すと、オブジェクトを操作した結果をRDBに反映=更新・追加・削除できるそうな。ただ、その実際のコードは、

[sourcecode language="c#"]
using(pubsEntities objCtx = new pubsEntities())
{
  titles titlesEntity = new titles();
  DateTime dt = DateTime.Parse("2008/09/17");
  titlesEntity.pubdate = dt;
  titlesEntity.royalty = 8;
  titlesEntity.title = "Tamaki";
  titlesEntity.title_id = "NO311";
  titlesEntity.type = "Family";
  objCtx.AddObject("titles", titlesEntity);
  objCtx.SaveChanges();
}

using (pubsEntities objCtx = new pubsEntities()) { titles titlesEntity = new titles(); titlesEntity = objCtx.titles.Where("it.royalty = 8").First(); titlesEntity.title = "Tamata"; objCtx.SaveChanges(); }

using (pubsEntities objCtx = new pubsEntities()) { titles titlesEntity = new titles(); titlesEntity = objCtx.titles.Where("it.royalty = 8").First(); objCtx.DeleteObject(titlesEntity); objCtx.SaveChanges(); } [/sourcecode]

みたいな感じになるんだって。一応オブジェクト操作でRDB上のデータをコントロールできてるけど、こんなやり方とても直観的で便利になったぜ!とは思えないなー。

DB上の行に対応したデータオブジェクトを操作して更新するのではなく、データオブジェクトを操作した後に、それをEDM側に更新 ・追加 or 削除するよ、と通知して、EDM側でその結果を反映させるのか。

この記事の最後の方で、この記事が書かれた時点でのユーザーの評価が書かれているけど、かなりネガティブな感じだね。その後少しは状況は変わったのかな?

Visual Studio 2010上で普通にDB接続ウィザードを使ったら、Entity Framework用の定義が自動生成されたから、推奨フレームワークなんだろうとそのまま使おうとしてみたんだけど、これはやめた方が良さそうな予感。

Entity Frameworkがらみの機能はがっつり削除して、ほかの方法で作り直す。下手したらSqlConnection使ってべたにSQL文を組み立てて書いた方がましかもしれないなー。ちょっとEntity Framework以外の手法を調べてみる。

Published At2011-11-02 04:11Updated At2011-11-02 04:11

技術日記
技術調査記録Edit

LINQ to SQL: リレーショナル データのための .NET 統合言語クエリ

前回、MySQL with tritonnに対して、LINQを使わず直接SQL文で全文検索を行った結果を、ページネーション用情報管理クラスに渡したところ、「クエリの結果を複数回列挙することはできません。」例外が発生したところからの続き。

結局RDBでLINQを使うときの詳しい仕様を把握しておかなければだめなんだねということで、上記もマイクロソフト公式ドキュメントをちゃんと読んでみることにする。

序盤に出てくるサンプルコードの、

[sourcecode language="c#"]
// DataContext で接続文字列を取得します。
DataContext db = new   DataContext("c:\northwind\northwnd.mdf");
[/sourcecode]
の部分って、コメントは「DataContext 接続文字列で取得します。」だよね。ずいぶん古いドキュメントっぽいけど、なんで直ってないんだろう。

で、なるほどサーバーエクスプローラを使ってDB接続して自動生成したクラスは、このDataContextってやつなのねとソースを見てみたら、なんか自動生成されたクラスの親クラスはDataContextじゃなくてObjectCotextになってるぞ。

ヘルプを見ると、DataContextクラスは「LINQ to SQL フレームワークのメイン エントリ ポイントを表します。」になっていて、ObjectContextクラスは「エンティティ データをオブジェクトとして、クエリや操作を実行するための機能を提供します。」になっている。

名前空間の階層で見ると、DataContextはLINQの機能で、ObjectContextはより上位概念であるEntity Data Modelの機能なのかな? とマイクロソフト用語を並べると理解した気になるけれども、LINQとかEntity Data Modelとかの意味(全体像)がわかってないので、そんなまとめ方に何の意味もありませんが、なにか?

機能としてはどっちもORM的なものを提供するための機能っぽいんだけど、どういう違いがあるのかまとめた説明はないのか?

LINQによるデータベース・アクセスとO/Rマッピング - @IT」を読むと、

  • VS2008世代のO/Rデザイナツールを利用して作るのが.dbmlファイル
  • これで自動生成されるクラスが、下記の二つ。
    • DataContextクラスを継承したエンティティクラス=テーブル定義と対応したクラス
    • DB接続やらSQL文の発行、エンティティクラスの生成や管理(ファクタリーっぽい?)を行うのがDataContextクラス
つまり、VS2008世代のO/Rマッピングは、DBレイヤーの処理を担当するDataContextクラスがあり、その下に具体的なテーブルとマッピングされるエンティティクラス群が存在する、という形。

というあたりで、やっぱりLINQに関してもっと基本的な部分を理解しておこうと、「LINQ(リンク)の基礎知識 - @IT」も読んでおくことにする。

  • クエリの戻り値はIEnumerable<T>オブジェクト
  • クエリが実行されるのは、クエリの結果がforeach文により処理されるとき(遅延実行)
  • クエリ結果に対してToArrayメソッドあるいはToListメソッドを呼び出せば、クエリが即時実行される
  • 通常のLINQクエリーを、等価のメソッド呼び出しに変換できる。from n in data where n.ShipCountry == "Norway" select n → data.Where(n => n.ShipCountry == "Norway").Select(n => n)
  • n => n.ShipCounter == "Norway" は、delegate(Orders n) {return n.ShipCountry == "Norway";}相当のラムダ式
  • 結果セットのカラムを絞りたい場合は、var records = from n in data where n.ShipCountry == "Norway" select new { OrderID = n.OrderID, EmployeeID = n.EmployeeID }; のように匿名クラスを使う。匿名クラスはクラス名がないのでvarで受け取る。
  • LINQクエリーをメソッド呼び出しに変換する際に使用したwhereやselectは拡張メソッド
LINQおよびDataContextについては、何となくわかってきた。

続いて、「第1回 最新DBアクセス・フレームワークの基本的な考え方 - @IT」でADO.NET Entity Frameworkについて学んでみる。

  • .NET Framework 3.5以降に搭載。.NET Framework 4で大幅に拡張
  • EDMはただのO/Rマッパーとは違う的な話をしてるけど、結局O/Rマッパーだよね
  • EDM(Entity Data Model) = CSDL(Conceptual Schema Definition Language: 概念スキーマ定義言語) + MSL(Mapping Schema Language) + SSDL(Storage Schema Definition Language) らしいが、なんかもう独自技術をてんこ盛りしすぎて理解する気になれないな
  • SSDL → MSL → CSDL という順序にRDBに近い側から抽象概念に近い側によってくるらしい。実際のRDBの実装を、3段階のレイヤーで抽象化しつつ、このEntity Data Modelという実装にマッチングさせているんだろうなー。
  • EDMの場合は、LINQではなく、Entity SQLとかObject SQLとか、SQLレベルで取り扱うのか? 最終的にはLINQにつなぎ込むみたいだけど、プログラマが直接扱うレイヤーとして、LINQの前にEDM専用のEntity SQLとかObject SQLとかいうレイヤーがあるらしい
というところまでで時間切れで今日はおしまい。

Published At2011-10-31 17:48Updated At2011-10-31 17:48

技術日記
技術調査記録Edit

とてもとても簡単な、jQueryプラグインのつくりかた。 | Ginpen.com

jQueryをライブラリとして使ったサイトを構築しているときに、独自のJavaScript機能群を実装したくなった場合、独自のクラスライブラリとして構築するよりも、実はそのサイト専用jQueryプラグインとして開発した方が、いろいろ便利だったりして。とふと思ったりした。jQueryプラグインは使うだけで作る方には興味がなかったけど、ちょっと試してみよう。

そういえば元はprototype.jsで作っていたサイトを、jQueryに載せ替えた(作業途中)。prototype.jsだとAjax呼び出し用のサーバーサイドAPIを、X-JSONヘッダを使って結果を返すように作っていた。これってjQueryに載せ替える場合は、jQuery側でわざわざX-JSONヘッダを読むように書くよりも、素直にレスポンステキストにJSONで結果を出力するようにした方がいいよなー。でも、JavaScriptライブラリの都合でサーバーサイドAPIまで書き直すのは、なんだかすごくいやな感じだ。

Apacheのログを分類して記録する方法

SetEnvIfを使って条件を識別できるようにする。あとは、CustomLog ~ env=~のようにログ出力する条件をCustomLogに追加する。

もう運営していないpingサーバー宛てのAPI呼び出しが大量にやってきて、そのせいでサーバーが重くなる。pingの呼び出しリクエスト自体は軽い処理にrewriteしているんだけど、ログ書き込みの負荷も馬鹿にならない。というわけで、

[sourcecode language="bash"] SetEnvIf Request_URI "/path/to/api" deny_api CustomLog  log/logFileName combined env!=deny_api [/sourcecode]

にした。

ASP.NET MVC+MySQL with tritonn

ASP.NETも久しぶり(数年ぶり)だし、ASP.NET MVCの方は初めてだし、LINQとか搭載されて以降の.NETによるDB操作はさっぱりわかっていない。

であるからには、これから書く話は実践的なノウハウではなく、よくわからないなりに何とか動くものを作ろうと努力する過程とその成果となる。このやり方がベストプラクティスかどうかなど、知るよしもない。

というエクスキューズをまずは書いておく。

環境としては、Visual Studio 2010+.NET Fraemwork 4.0+ASP.NET MVC 3+C#+MySQL with tritonnという、たぶんそんなに使われていない組み合わせだと思われる。

MySQLとの接続ドライバーとしては、MySQL純正(?)のADO.NET Driver for MySQL (Connector/NET)をインストールした。バージョンは6.4.3。今見たら6.4.4に上がっているようだけど、ひとまずいちいち追随しない。

既存のMySQLデータベースに接続するには、サーバーエクスプローラーからそれなりに設定で接続の追加を行う。標準のウィザードダイアログではたいした設定ができないので、基本的には詳細設定からちゃんと設定する。

特にCharacter Set(接続文字コード)をちゃんと設定しておかないと、一見ちゃんと動いているように見えつつ、データが化けたりする。私の場合は読み取り(select)だけはちゃんとできたりしたんで、なかなかこの設定が必要なことに気づけなかった。

データベースへの接続ができたら、それを元にEntity Data Modelを作成する。自動生成されるコードを見ると、ORマッパーみたいなものなんだろうけど、これがどこまで何ができるのかがいまいちわかりにくい。

で、Entity Data ModelとLINQを使うと、SQL文を文字列として構築する代わりに、テーブルクラスのオブジェクトをC#のコードレベルで操作しつつ、DBを扱うことができる。なかなか気色悪い構文で、

[sourcecode language="c#"] var db = new someDataEntities(); var list = from data in db.Tablename select data; [/sourcecode]

みたいな感じ。じゃあLINQを使って、tritonnの全文検索(SQL的にはmatch(field, filed, ..) against ('pattern'))を書こうと思ったけど、LINQで文字列検索ってcolumn.Contains(pattern)みたいな文字列部分一致検索で書く方法しか見つからず、これだとSQL的にはlike構文になってしまうらしい。

[sourcecode language="c#"] string searchword = "foo"; var list = from data in db.Tablename where data.field.Contains(searchword) select data; [/sourcecode]

みたいな感じね。でもこちとら、likeが使いたくないからtritonnを使っているんですけど。

LINQの範囲でmatch~against相当のSQLを実行する方法が見つからなかったんで、それならばSQL文を直接書く方法を探してみる。けれども、通常は(MS的には)標準的なLINQで書きつつ、どうしてもLINQでおさまらないところだけSQL文を使うようにしておきたい。全部SQLで書くのはきつい。

どうやら上記で言うところのdb(Entitiyクラス?)は、ExecuteStoreQueryメソッドで直接SQL文を使うことができるらしい。

[sourcecode language="c#"] string searchword = "foo"; var list = db.ExecuteStoreQuery("select * from tablename where match(field) against({0})", new object[]{searchword}); [/sourcecode]

こんな感じね。ただ、これだとlistの型が違ってしまうんで、その後の取り扱い方が変わってしまう。双方に共通しそうな型としては、

[sourcecode language="c#"] IEnumerable list; [/sourcecode]

あたりか? ひとまずこれでASP.NET MVCが対応している自動生成CRUDページのIndexにどちらの結果も渡すことができた。

でまあ全文検索付きインデックス用のリストは上記のような感じで取れるんだけど、これだと全件取得になってしまうんで、適当な件数ごとのページング処理を行いたい。単純に取得件数を抑えるだけならば、

[sourcecode language="c#"] int pagesize = 50; int page = 0; var list = list.Skip(page * pagesize).Take(pagesize).ToList(); [/sourcecode]

みたいにすればいい。ただ、これだといわゆるページネーション用のナビゲーションが作れない。その辺に対応したコードの書き方は、「NerdDinnerステップ8:ページングのサポート - @IT」で説明されている。指定したページサイズで計算した場合のトータルページ数とか前後のページが存在するか、などのナビゲーションに必要な情報を取得しつつ、取得する範囲を絞るPaginatedListクラスが肝。

で、それをそのまま適用してみたところ、SQL文でmatch~againstしているとPaginatedListクラスで「クエリの結果を複数回列挙することはできません。」という例外が出る。なんかやっぱりLINQの挙動について詳しく調べておかないと、何が起こっているのか把握できないか。以下次号?

Published At2011-10-28 23:56Updated At2011-10-28 23:56

技術日記
PHPからの乗り換え先を検討する その1Edit

なんだかんだでここ数年サーバーサイドの開発環境としては、PHP/Zend Frameworkをメインに使い続けてきた。けど、これから数年先を見据えた上で、これからもメインで使い続ける気がなくなったんで、乗り換え先を探すことにした。もちろん仕事ではまだまだ使うだろうけど。

まずはスクリプト言語の仲間である、Ruby/Python/Perlあたりを考えてみた。けれども、これらだと言語環境としてはPHPとそれほど大きな違いはないし、フレームワークや周辺ライブラリまで入れればそれなりに差が出るが、今からどれかに移行するほどのモチベーションがわかなかった。なんだかんだいって実用上は大きな差にならないし。

試す前は、Ruby/Ruby On Railsにかなり期待していたんだけど、この組み合わせは、お気軽に試しに採用してみるという感じではなさそう。これに決めたら深みにはまることを恐れずに心中する覚悟で使わないと、そのメリットを享受することができないように思える。まあ、高機能なフレームワークはどれもそういう傾向はあるんだけど。

あと、RubyもRuby On Railsもバージョン互換性を気にしなきゃいけない部分が目について、それが個人的には一番ネックに感じた。PHPを使い続けるのがいやになった理由の半分くらいは、最近&これからのPHPの言語仕様・環境レベルのアップデート状況にあるんで、移行してもバージョン間の非互換地獄にはまりたくない。ドキュメントの検索性の悪さもかなり悪印象。

JavaScriptは、どうせブラウザベースのクライアント向け言語としてこれからも使わなければならないから、サーバーサイドもJavaScriptにするのが言語環境の統一性があっていいかな、というのがあって、候補として非常に大きな存在。JITコンパイラが標準である分、実行速度も他のスクリプト言語より有利になりがちってところも魅力。ActionScriptと言語仕様が同じ分、Flashとライブラリとかある程度共有できたりするかもしれない、とか夢を見たり。

現状では、特にサーバーサイド開発言語としては、発展途上度が半端ない状態だけど、Node.js/WebSocketやjQuery、HTML5など、これからしばらくの間主流になりそうな技術がJavaScriptの周辺にはたくさんあるだけに、言語環境、関連ライブラリ、ドキュメントなどの開発・充実速度が非常に高そう。今から追いかけておけば、数年後の安定期にはだいぶ楽ができそうな気もする。

最初はそれほどでもなかったんだけど、調べ始めたらかなり有望に思えて来たのがC#/Monoもしくは.NET Framework。MSプロダクトを他OS環境に移植してバイナリ互換で動かせるようにしようなんて、所詮は絵に描いた餅のようなものだと思ってたんだけど、最近のMonoを使ってみたらなんだかちゃんと動いているっぽいじゃん。サーバーサイドでの実績はよくわからないけど、Linuxデスクトップ向けでは結構使われているらしいし。

C#/Monoも、JITで高速に動作するし、言語仕様的にもかなりわかりやすくて使いやすいし、ライブラリは充実しているし、VisualStudioというとても使いやすい開発環境もあるし(Windows環境ではね。他のOS環境ではMonoDevelopがあるけど、VSに比べるとだいぶ落ちるな。Eclipse+プラグインよりはましだけど)、仕事ではMS系の仕事はC#/.NET Frameworkがメインになるから、これでLinuxベースのサーバーサイドも開発できるなら非常にうれしい。

.NET FrameworkのWebアプリケーションフレームワークであるASP.NETは、初期の頃は仕事でやっていた。あれでちゃんと動くところはすごいけど、Web標準からみるときしょい仕組みだしサーバーがIISだしで、できれば使いたくない代物だった。今ならASP.NET MVCというきしょくないフレームワークがあるみたいだし、ApacheでASP.NETを動かすmod_monoなんてものも出ているみたいだし、Webアプリ開発も結構やりやすそう。

あと、MonoTouchを使うと、C#/.NET Frameworkを使ってiOSアプリとかAndriodアプリとかを作れるところもうれしい。ちょっとだけ試してみた感じでは、Xcode/Objective-Cで書くよりもかなり生産性が上がりそうだった。

UIViewController *controler = [[UIViewController alloc] init];
みたいなコードが
UIViewController controller = new UIViewController();
とか普通に書けるようになるし、UIデザインツール(Interface Builder)との連携も普通にイベントハンドラーを追加する感じで書けるし、一度こうやって書けることを知ってしまうと、Objective-Cで書く行為が今までよりも苦痛に感じてしまうようになる。あと、Cocoaのよくわからないクラスライブラリをあさらずに、.NET Fraemworkのクラスライブラリを使っていろいろ書けるのもとても楽。特にドキュメントの検索性的に。

ただ、MonoTouchは基本有償だし、iOSのアップデートにどこまで追随できるのかとか、いろいろ不安点はあるんだけど。

だいぶ話が逸れた。ともかくMonoはものすごく好印象だったのだが、サーバーサイド開発言語環境として考えると、マイクロソフト純正プロダクト以外での実績があまりにも少ないのが、かなり怖い。mod_monoなんかプロダクションレベルで使った実績ってあるんだろうか? 実際、MS環境で開発したASP.NETアプリをMonoで動かそうとして苦しんだ事例は見かけたけど、それ以外にMonoをサーバーサイド開発言語として使うような事例はほとんど見かけなかった。これは自分で茨の道を切り開いていかなければならない予感がする。

ただ、Monoの言語環境自体はそれなりに安定してそうだし、変にMS互換にしようと思わず、Mono環境で使える部分に絞って開発すれば、それなりに使い物になりそうな感触はある。あるいはASP.NETとかは使わず、HttpListnerを使ったAPIサーバーアプリとかを作る分には安定して使えそう。あと、個人的にはそれほど好きじゃないんだけど、使おうとすれば結構使えるSiliverlightも.NET Framework仲間だよね。

といった感じで、今のところJavaScript/Node.jsとC#/Monoが一歩ぬきんでている感じなんで、この二つを本格的に試してみるつもり。個人的なWebアプリをこの二つで作ってみて、どのくらい使えるかを検証してみる予定。

Published At2011-08-24 14:37Updated At2019-12-30 15:30