技術日記
技術調査記録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