EasySqlParser 1.1.2 をリリース

バグがあったので修正しました

null値をバインドできないという比較的致命的なバグでした。
今回の修正でnull値を渡すとDBNull.Valueとして渡されます。
nugetアップロード済みです。


しかしバグ報告とかもないのは使われてないということか 😢

nugetのダウンロードが全部スクレイピングとも思えないが(´・ω・`)

ChangeToken.OnChangeの罠

CI/CDとかクラウドとかまったく縁遠い中小企業にとっては.NET Framework初期のアプリの様に未だに設定ファイルをはじめ外部ファイルに大量依存、リリースも安心してできない、ブルーグリーンデプロイメントも当然できないといううれしくない状況なわけですが、そんな環境だと例えば外出しのSQLファイルだけ変えて仕様変更に対応するといったことをしたくなります。

で、.NET Coreにはファイルの変更を検知してゴニョニョするためのChangeToken.OnChangeという静的メソッドがあります。

docs.microsoft.com

ASP.NET Coreとあるがコンソールアプリでも問題ないので気にしない

簡単に実装できそうだったが、なぜか検知してくれなかった。
結論としてはIFileProviderWatchメソッドが絶対パスだとダメだったというオチだった。
なので正確にはPhysicalFileProvider.Watch(String) メソッドの仕様といったところなのかもしれない。

ChangeToken sample

Watchメソッドはglobパターンで複数のファイルをWatchできるが、変更されたファイル1つに対してのみ何かアクションを起こしたいとき1は、globパターンで使っていると都合が悪いのでそのような場合はサンプルのようにすればいいかと思います。


  1. XMLファイルをPOCOなクラスにデシリアライズして、ConcurrentDictionaryなどにキャッシュしておくとか

1978-2020

コービー・ブライアント事故死

彼を知る世界中の誰しもがこんなことになるとは想像もしていなかっただろう

かく言う私もそのうちの一人

あまりにも突然過ぎて実感がない

www.sportingnews.com

しかしNBA公式が彼の画像とともに出したこの「1978-2020」という数字が現実のもので受け入れるしかないと思いつつも、いまだに信じられないという気持ちもある

コービーとともにコートで戦った選手や、コービーに憧れてNBAに入った選手ならなおさらショックは大きいのだろう


常に努力し続けること1

それを教えてくれた彼は間違いなく私のメンターだった

デビュー時から引退までコービーをリアルタイムで見続けることができたのは今考えると幸せだったなと思う

ありがとう!コービー!

これからもITエンジニアの端くれとして戦っていこうと思う(自戒の意味も込めて)


  1. マンバメンタリティともいう

EasySqlParser 1.1.1 をリリース

バグがあったので修正しました

気付いた背景

知人からDb2のパラメータプリフィックス1@ じゃなくて : じゃね?
とツッコミが入ってそんなバカなと思い、確かめたものの結論としては @ のままでよかったのですが
そう言えば ODBC は位置パラメータしか使えないが確かめたっけ??

と、怪しくなったので確認すると

見事に落ちてしまったというわけです

まぁいまどき ODBCOLEDB を好き好んで使う人はいないと思いますが

各DB(IDbDataParameter実装型別)のパラメータプリフィックス

ついでなのでローカルでメモしていたものを共有するために書いておきます

DB IDbDataParameter実装 パラメータプリフィックス
SQL Server SqlParameter @
Db2 DB2Parameter @
As400 iDB2Parameter @
SQLite SQLiteParameter @
MySql MySqlParameter @
Oracle OracleParameter :
PostgreSQL NpgsqlParameter :

パラメータプリフィックスの参考資料


  1. と、私は読んでいるが正式名称は分からない

Nuget Packageの作り方

EasySqlParserでNuget Packageを作るときにハマったのでメモ

昔はCUI(Nugetコマンド)とかGUI(NuGet Package Explorer)とかでやってたましたが.NET Standardではdotnetコマンドでやります

cd プロジェクトファイルがあるディレクトリ
dotnet pack -c Release
rem デバッグシンボルも含める場合
rem dotnet pack -c Release --include-symbols

いやー、楽になったもんです

昔やったときはnuspecとかいうNugetパッケージを作るための元ネタ(ライブラリのバージョンとか依存関係とか)となるxmlを作る必要があったんですがそれは不要になりました

.NET Standardではそれらの情報をどこに書くかというとプロジェクトファイルに書きます

別ファイルに書くより断然楽です

Nugetパッケージができたらサーバにプッシュします

dotnet nuget push xxx.nupkg

ハマったところ

上記の情報はググればわりとヒットします

ハマったのは2019でやろうとしたときのことです

2017時代の情報はここに載っていますが、2019と比べると何かが違う

ライセンスが2017ではライセンスファイルへのURL指定だったものが2019では「MIT」とか「Apache-2.0」とか単なる文字列を指定するように変わっていました

どういう文字列ならいいのかという話ですが、これはSPDX識別子というもののようでここから選んで指定します

まとめ

.NET Standardでは…

  • ライブラリのバージョンの情報などはプロジェクトファイル(csprojとか)に書く

  • PackageLicenseExpressionはSPDX識別子から選ぶ

  • Nugetパッケージはdotnetコマンドで作る

おまけ

これを見る限りは以前に比べてプライベートリポジトリが増えているようなので、社内のライブラリでも利用するようにすれば管理が楽になると思います

参考

docs.microsoft.com

docs.microsoft.com

ASP.NET Coreのカスタムタグでハマった話

Javaではけっこうカスタムタグを作ったことがありますが、ASP.NET Coreではそのカスタムタグがかなり簡単に作れて感動しました

しかし少し凝ったことをしようと思ったら意外とハマったのでメモっておきます

何をしたいのか

<permissionControlManager>
    <input asp-for="Name"/>
    <input asp-for="Age" />
</permissionControlManager>
class PermissionControlManagerTagHelper : TagHelper
{
    // 省略
}

permissionControlManagerみたいなタグをまず作っておいて、
その中に適当にinputタグとが突っ込んだらpermissionControlManagerに囲まれた項目を条件(ユーザIDとかロールとか)によって読み取り専用、非活性、非表示とかにする

そこまでやるか??(´・ω・`) という気もしなくもないがそれはいったん置いておいて

外側のタグ(permissionControlManager)自体ものすごくシンプルなので問題ない

問題なのはその中に置くinputとかはそのinput自体が読み取り専用にしたり、非活性にしたりする必要があるので、通常のinput(ASP.NET Coreのinput=InputTagHelper)では使えない

そこで、そのInputTagHelperを継承して作ってやる必要が出てくるわけですが
どういうわけかhtmlのinput(≠InputTagHelper)までカスタムタグだと判断されてしまって半日ほど時間を無駄にしました

結果から行くとクラスに付ける HtmlTargetElement 属性の指定の仕方をミスってたというオチでした

// 1
// アカンやつ
[HtmlTargetElement("input")]

// 2
// これもアカンやつ
[HtmlTargetElement("input", Attributes = "asp-for", TagStructure = TagStructure.WithoutEndTag)]
// https://github.com/aspnet/AspNetCore/blob/master/src/Mvc/Mvc.TagHelpers/src/InputTagHelper.cs
// と同じもの

// 3
// イケてるやつ
[HtmlTargetElement("input", Attributes = "hoge, asp-for", TagStructure = TagStructure.WithoutEndTag)]

Attributesの中身で判断しているようで、

  • 1 Attributesが無いので全inputが根こそぎカスタムタグ扱いになる

  • 2 Attributesがあるが、デフォルトのInputTagHelperと同じなのでhtmlのinputはカスタムタグ扱いされないが、拡張したInputTagHelperも元のInputTagHelperも同じカスタムタグ扱いになる

  • 3 Attributesにデフォルトの「asp-for」のほかに「hoge」があるので、inputタグにasp-forとhoge属性があれば拡張InputTagHelperで、asp-forだけならデフォルトのInputTagHelper扱いになる

ドキュメントのAttributesの説明を見てもセレクタと書いてあるだけで今一つピンとこないのは英語慣れしてないからなのかな?

同じようなところでハマっている人がいたら HtmlTargetElement に気を付けてください

ドキュメントの補足 その1

動機は書き終わったのでドキュメントでは説明しきれないところなどを書いていこうかと思います

その1としてますが1だけで終わるかもしれませんw

名前

ソースコード中にも明記してますし、ドキュメントにも書いていますが
EasySqlParser内部のコードはDOMAの移植となっています

ならDOMA.NetとかnDOMAとかにしとくのがセオリーかもしれませんが、最初からDOMAを移植しようと思ったわけではありません

最初はパース処理を正規表現を駆使して、独自に書いていましたが、テストをしているとどうも遅いような気になって試しにDOMAを移植してみようかなと思って移植してみたら倍くらい速度が違いましたww

DOMAは1文字ずつ読み取っているから遅いんじゃないの?と高を括っていたのですがそんなことはなかった
10年くらい歴史があり、ググってたくさん情報が出てくるだけのことはあります

ちなみにEasySqlParserは最初から名前を決めていました
nugetを検索しても同じものが見つからないことを確認しながら…

また、DaoにもDomainにもマッピングのどれとも無関係なためDOMA.NetとかnDOMAと名付けるとか理解不能、理解不能(しげちー風)

マッピングとかせずに「単純にSQLをパースする」だけなのでそのまま名付けてEasySqlParserです1

なぜマッピングしないのにDB種別とか気にする必要があるのか

これはページングの際に必要だからです

ページングでは単一のSQLファイルからカウント文とデータ取得文を内部で生成しています
これ自体はDOMAパクリ移植です

ページングのSQLOFFSETLIMIT だったり、ROW_NUMBER だったりとDBによってかなり違います

これを実現するためにDBが何なのかの情報が必要になってくるわけです

しかし、つい最近ようやくMySQLROW_NUMBER がサポートされて、メジャーRDB(Microsoft SQL Server,Oracle,Db2,PostgreSQL,MySql,SQLite)すべてで ROW_NUMBER がサポートされました2
そこでEasySqlParserではオリジナルの機能として、DBの種別を無視してこの ROW_NUMBER を使用してデータ取得文を生成するようなオプションを用意しました

ドキュメントにもあるようにこのオプションを使用することでView層での行番号表示が容易に実現できます

これはサンプルアプリでも確認ができます


  1. nugetで同じ名前があったら別名になってましたが

  2. 他にもRDBはありますが気にしない