System.Data.SQLite で、日付型のラウンドトリップに失敗することがある

 SQLite の特徴の一つに「弱い型付け」があります。
それゆえ、PHPとか Ruby とかと相性がよいわけです。

が、それゆえに、.NET 系の「強い型付け」な言語と相性が悪かったりします。

先日遭遇したのは、こんな事例。

SQLiteに日付型のデータを入れて、取ってくるところでExceptionになる。
一言で言うと「ラウンドトリップできない」と。

ラウンドトリップ失敗の例

つまり、パラメータクエリで日付を渡すと、取得時に落ちるわけです。

原因は、” Now.ToString() “でした。
つまり、 DateTime.ToString を引数なしで呼び出すと、「地域と言語の指定」に従った「短い形式」で文字列にするわけです。日本の場合、一般的には “yyyy/mm/dd” 形式。

ですが、SQLite では “yyyy-mm-dd”形式 – 要するに、 ISO 8601 形式 (“T”は無くても良い)を日付として認識し、”yyyy/mm/dd”は日付として認識してくれない用なのです。

ためしに、コンソールでこんな風にやってみると…

sqlite> select datetime(‘2010-01-20′);
2010-01-20 00:00:00
sqlite> select datetime(‘2010/01/20′);

sqlite>

スラッシュ区切りは日付にあらずと言うわけです。が、そこは弱い型付けの SQLite、しっかりInsertは成功してるんですね。さらに、コンソールでのSelectも成功。 System.Data.SQLite で変換失敗というわけです。

解決策は意外と簡単で、
1)パラメータ渡すのにいちいち ToString しないで DateTime で渡す
2)どうしても ToString したかったら、 ToString(“s”) を使う。
3)DataSet を使う

データセットを使ってみた例

相手が SQL Server とか Oracle とかなら、そもそもコンパイルか Insert 時にエラーになりそうですが、 SQLite の場合にはこうなりますってことで。

SQLite の日付はUTC

 SQLite って何ってのは、とりあえずググって下さい。 本家はコチラ www.sqlite.org 。

どうやって落とすか、インストールするか、使うかってのも、色々リソースがあるので省略。
どうやってDataSetをデザインタイムでいじるのかってのも、コチラ http://sqlite.phxsoftware.com/ から。
で、本題。SQLite での日付型は、UTCで管理されるというオハナシ。
たとえば
CREATE TABLE test2(id int, name text, UpdateDate datetime);
なんてのがあって、
insert into test2 values(1,’Tokyo’,datetime(‘now’));
なんてカマして安心していると、中に入っているのはUTCというコトです。

安心しきってると、日付データがもれなく9時間ずれます。プログラム内で現在時刻と比較したり、SQL Server とかと比較したりすると、軽めに死ねそうです。

で、どうするか。

1) SQLを工夫する
select datetime(UpdateDate,’localtime’) from test2;
とすると、ローカルタイムに変換してくれます。
データセットデザイナでやると、型推論がうまくいかないのか、Object型になっちゃうのが難点。

2) DataSet でなんとかする
DataSet – DataTable の当該行を選択してプロパティ→DateTimeMode を”Utc”に変更。
そうすると、DateTime の Kind プロパティが “Utc”になるので、ToLocalTime してOK。

3) コード内でアレコレ
DBから取ってきてそのまま突っ込んでも、”Kind”プロパティが”Unspecified”のママです。ようするに、「時刻がUTCか地方時なのか知らないけど、とにかく入ってるよ。」状態ってことです。
まぁ、確かに日本は夏時間もないのでそのまま9時間加算してあげれば良いような気もします。ただ何となく個人的にどうにも居心地が悪いのです。
やるとすれば、こんな感じかなと…

‘—-まずはDBから取ってきた生の状態が DateTime の中身。
Dim dteResult As DateTime = CDate(objCommand.ExecuteScalar())
‘—-これをUTC時刻として(つまりオフセット0で) DateTimeOffset に入れる。
Dim dtoLocal As New DateTimeOffset(dteResult, New TimeSpan(0))
‘—-ここで、地方時を呼び出す
Console.WriteLine(dtoLocal.LocalDateTime)
‘—-これできちんと地方時に変換されました。


ま、どの方法がどうこうもあるけど、知っとかないと痛手くらいそうな場所なのでメモ。

自家製ObjectをTreeView等に突っ込む時の注意点

軽めに嵌りそうになったのでメモ
MSDN-Windows Presentation Foundation データ テンプレートの概要
つまり、TreeViewとかListBoxとかが表示する時にはデフォでToStringを使うってこと。
ここで軽めに嵌ったのは、
○:Public Overrides
×:Public Overloads
×:Friend Overloads
コンパイルエラー:Friend Overrides
というポイント。むやみやたらとスコープを狭くするクセのある人は注意。

Try-Catch のネストに関するメモ

こんなネストを書くのは如何かと思いながらも、こんなコード。
[VB.NET]

    Sub Main()
        Try
            Try
                Throw New ApplicationException(“test”)
            Catch ex As Exception
                Console.WriteLine(“Caught: Level 2″)
                Console.WriteLine(ex.Message)
            End Try
            Console.WriteLine(“End of normal line of Level 1″)
        Catch ex As Exception
            Console.WriteLine(“Caught: Level 1″)
            Console.WriteLine(ex.Message)
        End Try
        Console.WriteLine(“Hit any key…”)
        Console.ReadKey()
    End Sub

で、コレの結果は

Caught: Level 2
test
End of normal line of Level 1
Hit any key…

Exceptionは握り潰されました。
じゃぁこれは?

    Sub Main()
        Try
            Try
                Throw New ApplicationException(“test”)
            Catch ex As Exception
                Console.WriteLine(“Caught: Level 2″)
                Console.WriteLine(ex.Message)
                Throw ’<-これを追加             End Try             Console.WriteLine("End of normal line of Level 1")         Catch ex As Exception             Console.WriteLine("Caught: Level 1")             Console.WriteLine(ex.Message)         End Try         Console.WriteLine("Hit any key...")         Console.ReadKey()     End Sub

結果は…

Caught: Level 2
test
Caught: Level 1
test
Hit any key…

こっちはExceptionが伝播しました。
どっちが欲しいのかは状況によって代わるので、きちんと理解しておかないと後で辛いと。

MSDN ライブラリ 低帯域 Version

kkamegawaさんに教えてもらいました-コチラの記事です。
これで、帯域幅が貧弱なウチの職場でも安心♪
なんですが、これだけではおもしろくないので、もう一歩。
通常版-英語
http://msdn.microsoft.com/en-us/library/cc488280.aspx
通常版-日本語
http://msdn.microsoft.com/ja-jp/library/cc488280.aspx
低帯域-英語
http://msdn.microsoft.com/en-us/library/cc488280(loband).aspx
低帯域-日本語
http://msdn.microsoft.com/ja-jp/library/cc488280(loband).aspx
低帯域版も、ちゃんと日本語対応してんでやんの♪
ありがたい話です。
ちなみに、大元ネタの VB Team blog の記事はコチラです。

最小構成の組織について

景気の良くないニュースばかり聞こえてくるこの頃でございますが、皆様如何お過ごしでございましょうか。ご多分に漏れずそういうキーワードがあちらこちらから耳に入ってくるわけです。
不景気なキーワードと言えば思い出すのが、最初の職場で私を仕込んでくれた師匠のうちのお一方が吐いた台詞。

電気消すより役に立たんオヤジの一人でも消した方が、よっぽど効果あるわ。

誠にごもっとも。諸手を挙げて賛成です。
が、往々にして、そう言われる人々は「既得権」の安全圏に居るわけで、標的にされるのは現場の下々と相場は決まっています。
ここで腕に確かな覚えと、十分な預金残高があれば威勢の良い啖呵が切れると言うものです(備えあれば憂いなし!)
ですが、問題はその後-残される側の話。
F.Brooks の法則(というか呪い?)が指摘するとおり、人の教育にはリソースが必要で、その期間中は生産性がマイナス方向に変化する訳です。この事を頭に入れた上で、次の状況を考えてみます。
1)組織を「最小構成」にまでリストラする
  つまり、全員が100%近い稼働率でなんとか仕事を回せる状態にまで人を減らす。
2)「余計な出費」、特に残業代・外注費は罷り成らんというお達しが、「その筋」より発せられる。
3)この状態で、何かのプラス方向の変化、つまり仕事が増える方向の変化が発生する。
  例えば、営業部門が必死の努力で新ネタを拾ってきた。
さて、この状態。経験のある現場担当者なら背筋に冷たい物が走る-走って然るべき状況です。
既に稼働率は100%近く。外だしも要員補充も罷り成らんどころか、そのためのオーバーヘッドすら吸収する余地がない。つまり、要員構成としては「手詰まり」な状況です。
これでマネージャーに何をしろと??
ここで、現場マネージャーが打てる手は…
無償の残業(サービス残業、或いは「パケ放題」な管理職を残業させる)により、なんとか仕事をこなすぐらいです。
前者は士気を完膚無きまでに地に落とし(そして訴訟リスクを背負い)、後者は組織としての『学習』が無いままに-つまり組織としての未来を得ること無しに-それぞれ前に進むだけです。そして、彼らが燃え尽きて去っていった後には、ペンペン草一つ生えない、不毛の荒野が残るだけ。
確かに、明日のビフテキより今日の掛蕎麦。それは否定する気はありません。しかし、一所懸命働いているスタッフに夢の一つも見せられない、「今日のメシが食えるだけシアワセと思え」な職場。首切りが怖くて残っているヤツばかりの職場(=腕に覚えのあるヤツはさっさと自分の意志で去っていく)
それってどうなのよ、そんな組織で本当にいいの??と言いたくなる今日この頃だったりします。

悪魔の代理人としての現場管理者

部下に対しての話じゃなくて、上司に対しての話。
いつものように上司にお白州に呼び出されて、プロジェクトに現状を言上するわけです。
その時心がけていること。
耳障りの悪いことを敢えて言うこと
つまり
・耳障りの良いことばかり言うヤツは要らない
順風満帆万事順調、そんなオメデタイ仕事なんぞある訳がないので、どこかにリスク要因があり、どこかに問題があるはずです。
それを見つけ出してアラートをあげるのも、現場管理者の重要な仕事のはずです。
で、そういう情報は上層部としては耳障りが良かろうはずがなく、
従って、最後は「なんでおまえは物事に対してそう悲観的なんだ!」仕舞いには「要するにやる気がないんだろ!」とか、そういうコトを言われる場合もあるでしょう。
が、毎回「順調です」と報告しておいて、突然(いつものように)大炎上が始まるのと、どちらがあるべき姿かという議論はするまでもないでしょう。
なので、現場管理者は上司に対して悪魔の代理人のように、悪い報告の方を重点的にあげる必要があると思うわけです。
で、上司がそういう報告に耳を貸さない、する度に(上記の例のように)怒鳴りつけられるとあれば、それは履歴書をアップデートするべき時でしょう。
但し、『ものには言い方ってもんがある』ことを心がけておく必要はあります。

oramts.dll はドコにいる?

Oracle Services For Microsoft Transaction Service の話。
やってて怒られた(DLLNotFoundException)ので、一体どこから落とせるんだ?と探した結果は、灯台もと暗し。
OTN辺りから落としてくるのではなく、Oracle client インストール時のオプションで入るのです。
デフォルトの「開発者」「instant client」では入らないので、「カスタム」を選択して、”Oracle Services For Microsoft Transaction Service ” にチェックを入れる必要があります。
ググりまくってかなり時間を浪費したのでメモと言うことで。

SQL Express で複数インスタンス存在する場合にIPのみで接続する方法

SQL Server Express で複数のインスタンスがあり、かつ、接続使用とするツールの「接続設定」に「IP」しか無い場合の設定方法。
普通の場合は、[サーバー名]¥[インスタンス名] で接続できます。
(Expressではない) SQL Server の Management Studio からもこれで接続できます。
が、そうではないツール類で、そういう入力が出来ない場合。ありがちな例としては、
・サーバーのIPアドレス(ご丁寧にガチ入力チェック付き)
・データベース名
・ポート番号
・ログインID/パスワード
しか入力できない場合-インスタンス名が入れられないのです。
こういう場合は、
「構成マネージャー」から「ネットワークの構成」→「[インスタンス名]のプロトコル」で、TCP/IPを右クリックして「プロパティ」。出てきた画面の「IPアドレス」のタブをクリック。
一番下に「TCPポート」と「TCP動的ポート」があるので、それがそのインスタンスのポート番号です。
このポート番号を指定して接続できます。
で、ポート番号も指定できないような状況なら、インスタンスのポート番号を規定値(1433)に変更してしまうのも一法でしょう(きっと)。

Oracle SQL Developer

Oracle上での開発作業と言えば”SI Object Browser“。
コレがなければ夜も日も明けない。
が、それの本家版、Oracle SQL Developer
Oracle製である上に無償(DB本体のライセンスがあることが条件)。
と、言うことで使ってみた感想とその罠とかのメモ。
・良くも悪くもOracle風。SQL Server ばかりやってきた目からすると、「かゆいところに手が微妙に届かない」
・SQL Server, Access, MySQL に接続可能
・PL/SQLのデバックも出来る…らしい(まだ試してない)
・SQL Server からの移行ツールはなかなか出来がよい
・が、やはり全自動というわけにはいかない(それでも凄い)
・生成されるSQL文、一部で「引用符が欠落してエラーになってしまう」問題がある
・11gに同梱のモノはバージョンが古いので、最新(1.2)を落としてくる必要がある
・頑張れば1.5が米国から落とせるらしいが、労多くして功少なし
・例によって英語
・エラーを返すのは良いのだが、意味不明(メッセージすら返却しない)ことがある。
・結果ペインのグリッド表示って無いの??
とまぁ色々あるのですが、実際にはかなり使えることも事実。
まぁ、こんなのもありますよってことで。