(追記アリ)
DapperのSQLプレースホルダでコーディングミスをしたので対応策の備忘録です。
文字列でのパラメータ指定が大嫌いなんです
DapperやADO.NETはSQL中に"@“から始まる文言を用いることでプレースホルダを表現できます。
例えば下記の例では”@userId"がプレースホルダとなり、"new {userId = 1}“にてパラメータを指定しています。
var sql = @" Select u.* From Users as u Where u.Id = @userId "; using (var conn = new SqlConnection(connectionstring)) { var user = conn.QueryFirstOrDefault<User>(sql, new { userId = 1}); }
今回は、この無名クラスのuserIdをタイポして実行時エラーとなりました。
System.Data.SqlClient.SqlException: 'Must declare the scalar variable "@userId".'
すぐに気が付くようなエラーなので大したことではなかったのですが、やはり実行時エラーは気に入りません。
静的型付言語を使っている以上コンパイル時に最大限エラーを発見したいものです。
対応策1. nameofとDynamicParametersを使う
SQL文の中のプレースホルダが文字列になっているのがそもそもの原因です。
nameofを使ってコンパイラの監視下に置きましょう。
//userId = 1 が与えられているとする var sql = $@" Select u.* From Users as u Where u.Id = @{nameof(userId)} "; var param = new DynamicParameters(); param.Add(nameof(userId), value: userId); using (var conn = new SqlConnection(connectionstring)) { var user = conn.QueryFirstOrDefault<User>(sql, param: param); }
対応策2. nameofと別の型を使う
あるいはこんな風に書いても動作します。
入力パラメータ専用のDTOを作成するか共用するかは設計次第でしょうか。
//userId = 1 が与えられているとする var u = new User() { Id = userId }; var sql = $@" Select u.* From Users as u Where u.Id = @{nameof(User.Id)} "; using (var conn = new SqlConnection(connectionstring)) { var user = conn.QueryFirstOrDefault<User>(sql, param: u); }
(追記)対応策3. nameofと無名クラスを使う
すっかり忘れていましたが、こういう方法もありました。
//userId = 1 が与えられているとする var sql = $@" Select u.* From Users as u Where u.Id = @{nameof(userId)} "; using (var conn = new SqlConnection(connectionstring)) { var user = conn.QueryFirstOrDefault<User>(sql, param: new { userId }); }
まとめ
nameof演算子は便利ですね。