NPocoの紹介 -カスタマイズ編- 空文字列をnullに変換して登録する

# NPocoの紹介 -カスタマイズ編- 空文字列をnullに変換して登録する
最初の記事は[こちら](https://qiita.com/epsilon_87_myo/items/1c0f75064b9b6bcc9e1e)

今回はカスタマイズ方法についての紹介です。

## 注意
このカスタマイズ方法は公式で紹介されているものではなく、私が独自で行っているものです。

あらかじめご注意ください。

## やること
InsertやUpdateにおいてパラメータに空文字列が含まれていた場合、これをnullに変換して登録する。
(「複数DBベンダー対応をする際にOracleの挙動に合わせるため」 などが動機として考えられます。
というか私はそれでした😀)

## 方法１ `Database` クラスの `AddParameter` をオーバーライドする。
一つ目の方法は `Database` クラスそのものを継承し、`AddParameter` クラスの挙動を変更します。

```cs:MyDatabase.cs
public class MyDatabase : Database
{
    public MyDatabase(DbConnection connection) : base(connection) { }

    public override void AddParameter(DbCommand cmd, object value)
    {
        if (value is string s)
        {
            if (string.IsNullOrEmpty(s))
            {
                //空文字列ならnullで親のメソッドを呼ぶ
                base.AddParameter(cmd, null);
                return;
            }
        }
        //それ以外はそのまま
        base.AddParameter(cmd, value);
    }
}
```

実行コード

```cs
using MyDatabase database = new MyDatabase(con);
database.Insert(new Emp
{
    EmpId = "EX01",
    FirstName = "",
    FamilyName = "",
    DeptCode = "X01",
    CreatedAt = new DateTime(2020, 6, 30),
    UpdatedAt = new DateTime(2020, 6, 30),
});
```

実行ログ

```
INSERT INTO "emp" ("emp_id","first_name","family_name","dept_code","created_at","updated_at") VALUES (@p0,@p1,@p2,@p3,@p4,@p5)
         -> @p0 [String] = "EX01"
         -> @p1 [DBNull] = ""
         -> @p2 [DBNull] = ""
         -> @p3 [String] = "X01"
         -> @p4 [DateTime] = "2020/06/30 0:00:00"
         -> @p5 [DateTime] = "2020/06/30 0:00:00"
```

p1, p2が`[DBNull]` となっていることから`null` で登録されていることが確認できます。


## 方法２ `IMapper` の `GetParameterConverter` を使用する。
[IMapper](https://github.com/schotime/NPoco/blob/d707af2bf59f5c70c1d147bc6974d3cdd52bb05b/src/NPoco/IMapper.cs) というインターフェースが用意されており、これを利用すると、データベースから結果を取り出すときや、データベースへ登録するときに 変換処理などを行うことが可能です。

今回はこの`IMapper` の `GetParameterConverter` メソッドを利用します。

このメソッドは前述の`Database.AddParameter` で実行されています。

また`IMapper` を直接実装するのではなく、あらかじめ用意された[DefaultMapper](https://github.com/schotime/NPoco/blob/d707af2bf59f5c70c1d147bc6974d3cdd52bb05b/src/NPoco/DefaultMapper.cs)を継承して作成します。

```cs:MyMapper.cs
public class MyMapper : DefaultMapper
{
    private readonly IDictionary<Type, Func<object, object>> _converters = new Dictionary<Type, Func<object, object>>
    {
        [typeof(string)] = s => string.IsNullOrEmpty((string)s) ? null : s,
    };


    public override Func<object, object> GetParameterConverter(DbCommand dbCommand, Type sourceType)
    {
        if (_converters.TryGetValue(sourceType, out Func<object, object> converter))
        {
            return converter;
        }
        return base.GetParameterConverter(dbCommand, sourceType);
    }
}
```


実行コード

```cs
using Database database = new Database(con);
database.Mappers.Add(new MyMapper());

database.Insert(new Emp
{
    EmpId = "EX01",
    FirstName = "",
    FamilyName = "",
    DeptCode = "X01",
    CreatedAt = new DateTime(2020, 6, 30),
    UpdatedAt = new DateTime(2020, 6, 30),
});
```


実行ログ

```
INSERT INTO "emp" ("emp_id","first_name","family_name","dept_code","created_at","updated_at") VALUES (@p0,@p1,@p2,@p3,@p4,@p5)
         -> @p0 [String] = "EX01"
         -> @p1 [DBNull] = ""
         -> @p2 [DBNull] = ""
         -> @p3 [String] = "X01"
         -> @p4 [DateTime] = "2020/06/30 0:00:00"
         -> @p5 [DateTime] = "2020/06/30 0:00:00"
```

`Database.AddParameter` と同様の結果になっています。

## 注意点
これらの方法ですが、全てのパラメータマッピング時に実行されるため、SELECTを実行する場合でも呼び出されてしまいます。
(アプリの仕様によってはこれが害になる可能性もあります。)

またSELECT + INSERT, SELECT + UPDATE のようなパラメータを介さないものについてはこれらのメソッドが実行されてないので、変換は行われません。