C#

【C#】DapperExtensionsの使い方

「DapperExtensions」の使い方をまとめます。
DapperExtensionsはDapperをより手軽に使うことのできる拡張ライブラリです。
単純なSELECTやINSERTなどであればSQL文を書く必要が無くなります。

【検証環境】.NET 5.0 / SQL Server 2019 localDB

利用準備

パッケージのインストール

PM> Install-Package DapperExtensions

https://www.nuget.org/packages/DapperExtensions

DBとテーブルの作成

DBとデータはこちらの記事で作成したものと同じものを使いますので省略します。

マッピングモデルの作成

マッピング用のモデルクラスも上記と同様ですので省略します。

DapperExtensions ではDBのカラム名がスネークケースではエラーになってしまいます。
その場合、マッピングモデルでアンスコを使わないでプロパティを定義して、こちらのクラスで列名とプロパティを紐づければ解決します。

スネークケースに限らず、ClassMapperで紐づけを行えば列名とプロパティ名は一致させる必要はありません。

通常のDapperであればスネークケースでも問題ありません。

使い方

https://github.com/tmsmith/Dapper-Extensions

SELECT

Get

SELECTで1レコードのみ取得したい場合はGet メソッドを使用します。

using Dapper;
using DapperExtensions;
using System;
using System.Data.SqlClient;

//接続文字列
var connectionString = "接続文字列";
using (SqlConnection cn = new SqlConnection(connectionString))
{
    cn.Open();
    //引数に主キーを渡す
    var person = cn.Get<Person>(new Person() { ID = 2 });
    //下記のような書き方でもいける
    //var person = cn.Get<Person>(2);
    //var person = cn.Get<Person>(new { ID = 2 });

    Console.WriteLine(person.ToString());
    //本田翼:28歳
}

GetList

SELECTで複数レコード取得したい場合はGetList メソッドを使用します。

using Dapper;
using DapperExtensions;
using System;
using System.Data.SqlClient;

var connectionString = "接続文字列";
using (SqlConnection cn = new SqlConnection(connectionString))
{
    cn.Open();
    var people = cn.GetList<Person>();

    foreach (var person in people)
    {
        Console.WriteLine(person.ToString());
    }
  //永野芽郁:21歳
  //本田翼:28歳
  //戸田恵梨香:32歳
}

INSERT

INSERTを行いたい場合はInsert メソッドを使用します。
引数にはListで渡すことも可能です。※ただし、INSERT文自体は1件ずつ発行されます。

using Dapper;
using DapperExtensions;
using System;
using System.Data.SqlClient;

var connectionString = "接続文字列";
using (SqlConnection cn = new SqlConnection(connectionString))
{
    cn.Open();
    var person = new Person(){Name = "川口春奈", Age = 26,};

    cn.Insert(person);

    //Listでも渡せる
    var people = new List<Person>() 
    {
        new Person() { Name = "深田恭子", Age = 38 }, 
        new Person() { Name = "綾瀬はるか", Age = 36 }
    };
    cn.Insert(people);
}

UPDATE

UPDATEを行いたい場合はUpdate メソッドを使用します。
引数にはListで渡すことも可能です。※ただし、UPDATE文自体は1件ずつ発行されます。

using Dapper;
using DapperExtensions;
using System;
using System.Data.SqlClient;

var connectionString = "接続文字列";
using (SqlConnection cn = new SqlConnection(connectionString))
{
    cn.Open();

    var person = cn.Get<Person>(new { ID = 3 });
    ////更新したい処理
    cn.Update(person);

    //Listでも渡せる
    var people = cn.GetList<Person>();
    ////更新したい処理
    cn.Update(people);
}

DELETE

DELETEを行いたい場合はDelete メソッドを使用します。
引数にはListで渡すことも可能です。※ただし、DELETE文自体は1件ずつ発行されます。

using Dapper;
using DapperExtensions;
using System;
using System.Data.SqlClient;

var connectionString = "接続文字列";
using (SqlConnection cn = new SqlConnection(connectionString))
{
    cn.Open();

    var person = cn.Get<Person>(new { ID = 3 });
    cn.Delete(person);

    //Listでも渡せる
    var people = cn.GetList<Person>();
    cn.Delete(people);
}

応用編

等号以外の条件でSELECT

等号以外の条件を使いたい場合はPredicates クラスのField メソッドを使用します。
以下は年齢が30歳以上のデータをSELECTする例です。

using Dapper;
using DapperExtensions;
using System;
using System.Data.SqlClient;

var connectionString = "接続文字列";
using (SqlConnection cn = new SqlConnection(connectionString))
{
    cn.Open();

    //年齢が30歳以上
    var predicate = Predicates.Field<Person>(p => p.Age, Operator.Ge, 30);
    var people = cn.GetList<Person>(predicate);
    foreach (var person in people)
    {
        Console.WriteLine(person.ToString());
    }
  //戸田恵梨香:32歳
}

引数の説明と演算子の種類は下記のとおりです。

第1引数カラム
第2引数演算子
第3引数
第4引数NOTの場合のみfalse指定
引数
Operator.Eq=
Operator.Gt>
Operator.Ge>=
Operator.Lt<
Operator.Le<=
Operator.LIKELIKE
演算子

複数条件でSELECT

複数条件でSELECTしたい場合はPredicateGroup クラスを使用します。

using Dapper;
using DapperExtensions;
using System;
using System.Data.SqlClient;

var connectionString = "接続文字列";
using (SqlConnection cn = new SqlConnection(connectionString))
{
    cn.Open();

    var predicates = new PredicateGroup() 
    { 
        //OperatorにAND か ORを指定
        //Predicatesに条件をAddしていく
        Operator = GroupOperator.And, Predicates = new List<IPredicate>() 
    };
  //25歳以上 AND 30歳以下
    predicates.Predicates.Add(Predicates.Field<Person>(p => p.Age, Operator.Ge, 25));
    predicates.Predicates.Add(Predicates.Field<Person>(p => p.Age, Operator.Le, 30));
    var people2 = cn.GetList<Person>(predicates);
    foreach (var person in people2)
    {
        Console.WriteLine(person.ToString());
    }
  //本田翼:28歳
}

ORDER BY

ソートをしたい場合は IList<Isort>オブジェクトを生成し、条件を指定してGetList メソッドの第2引数に渡します。
複数カラムでソートしたい場合はIList<Isort>に適宜条件を追加します。

using Dapper;
using DapperExtensions;
using System;
using System.Data.SqlClient;

var connectionString = "接続文字列";
using (SqlConnection cn = new SqlConnection(connectionString))
{
    cn.Open();

    //昇順
    var predicate = Predicates.Field<Person>(p => p.Age, Operator.Ge, 20);
    var sort = new List<ISort>() { new Sort() { PropertyName = "Age", Ascending = true} };
    var people = cn.GetList<Person>(predicate, sort);

    //降順
    var predicateDesc = Predicates.Field<Person>(p => p.Age, Operator.Ge, 20);
    var sortDesc = new List<ISort>() { new Sort() { PropertyName = "Age", Ascending = false } };
    var peopleDesc = cn.GetList<Person>(predicate, sortDesc);
}

IN

IN句を使用したい場合はField メソッドの第3引数にコレクションで渡せば内部でIN句に変換されます。

using Dapper;
using DapperExtensions;
using System;
using System.Data.SqlClient;

var connectionString = "接続文字列";
using (SqlConnection cn = new SqlConnection(connectionString))
{
    cn.Open();

    var names = new string[] { "本田翼", "戸田恵梨香" };
    var predicateIN = Predicates.Field<Person>(p => p.Name, Operator.Eq, names);
    var peopleIN = cn.GetList<Person>(predicateIN);
}

COUNT

COUNT句を使いたい場合はCount メソッドを使用します。

using Dapper;
using DapperExtensions;
using System;
using System.Data.SqlClient;

var connectionString = "接続文字列";
using (SqlConnection cn = new SqlConnection(connectionString))
{
    cn.Open();

    var predicateCOUNT = Predicates.Field<Person>(p => p.Age, Operator.Ge, 25);
    var count = cn.Count<Person>(predicateCOUNT);
}

主キーが複数の場合

主キーが複数の場合は事前に準備しておくべきことがあります。
列名とプロパティ名が異なる場合もこちらで紐づけを行う必要があります。
下記のような主キーが2つの場合を例にします。

public class Data
{
    public string Key1 { get; set; }
    public string Key2 { get; set; }
    public string Value { get; set; }
}

まず、任意の場所に下記クラスを定義します。

using DapperExtensions.Mapper;

public sealed class CustomClassMapper<T> : ClassMapper<T> where T : class
{
    public CustomClassMapper()
    {
        if (typeof(T) == typeof(Data))
        {
            //複数主キーの設定
            //Column は列名とプロパティ名が同じなら不要?
            Map(x => (x as Data).Key1).Column("Key1").Key(KeyType.Assigned);
            Map(x => (x as Data).Key2).Column("Key2").Key(KeyType.Assigned);

            //列名とプロパティの紐づけ(異なる場合)
            Map(x => (x as Data).Value).Column("列名");
        }
        //AutoMap()で残りの設定は自動で紐づけ
        AutoMap();
    }
}

そして、アプリケーション起動時に下記コードを実行します。

DapperExtensions.DapperExtensions.DefaultMapper = typeof(CustomClassMapper<>);

すると、下記のようにGet メソッドに主キーを複数指定することができます。

using Dapper;
using DapperExtensions;
using System;
using System.Data.SqlClient;

var connectionString = "接続文字列";
using (SqlConnection cn = new SqlConnection(connectionString))
{
    cn.Open();

    var data = cn.Get<Data>(new { Key1 = 1, Key2 = 1 });
}
エンジニアの転職ならこれ!

【第二新卒向け】マイナビジョブ20's

マイナビジョブ20'sは、20代・第二新卒・既卒向けの転職エージェントです。

▼こんな方におすすめ
・はじめて転職しようと思っている
・転職できるだけのスキルが自分にあるか不安
・手厚いサポートを受けたい

【フリーランス向け】 Midworks

Midworksは豊富な案件と「フリーランス」と「正社員」の良いとこ取りをした働き方を実現する手厚い保障が特徴です。

▼こんな方におすすめ
・現在正社員でフリーランスになろうか悩んでいる
・フリーランスとして働いているが、先行きが不安がある  (安定的な案件確保や保障など)
・自分の市場価値を知りたい、見合った案件で参画したい
・今後のキャリアビジョンを踏まえて案件を選びたい