4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

C#でDapperで動的Where句をSQL Builderを使わずに実現したい

Last updated at Posted at 2023-08-10

1. はじめに

  • Dapperを使用してDBのデータを取得したい
  • 動的Where句をSQL Builderでロジックに記述せずにSQLだけで実現したい
  • 動的Where句で、かつIN句の場合に発生した問題(口述)をなんとか回避したい

2. 開発環境

  • C#
  • .NET 6
  • Visual Studio 2022
  • SQLite
  • DB Browser for SQLite
  • Dapper (NuGet)
  • System.Data.SQLite.Core (NuGet)
  • ToString.Fody (Nuget)

3. 開発環境の準備

3.1. Dapperのインストール

  • NuGetよりDapperをインストールする
    image.png

3.2. System.Data.SQLite.Coreのインストール

  • NuGetよりSystem.Data.SQLite.Coreをインストールする
  • DBは今回SQLiteを使用するため準備する
    image.png

3.3. ToString.Fodyのインストール

  • NuGetよりSystem.Data.SQLite.Coreをインストールする
  • DBの検索結果を簡単に確認するために準備する
    image.png

3.3. DB Browser for SQLiteのインストール

  • 下記サイトよりインストーラーをダウンロードして、インストールする
  • SQLiteのDB参照のために準備する
    image.png

4. テストDBの作成

4.1. データベースの作成

  • DB Browser for SQLiteを起動して、新しいデータベース作成をクリックする
    image.png

  • 任意のフォルダ、ファイル名で保存する
    image.png

4.2. テーブルの作成

  • SQLの実行タブよりCREATE文を入力して、実行ボタンをクリックする
    image.png
CREATE TABLE "Person" (
	"Id"	varchar(8) NOT NULL,
	"Name"	varchar(40) NOT NULL,
	"Age"	INTEGER,
	PRIMARY KEY("Id")
)

4.4. テストデータの投入

  • データ閲覧タブより新規レコード挿入ボタンをクリックする
    image.png

  • カラムに値を入力後に、変更を書き込みするボタンをクリックしてコミットする
    image.png

5. サンプルコード(固定SQL)

5.1. DTOクラス

  • [ToString]属性を追加することでプロパティを含めて出力することができる
PersonDto.cs
[ToString]
public class PersonDto
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public int Age { get; set; }
}

5.2. DBアクセスクラス(抜粋)

  • 通常の値のDynamic Object以外にIN句はList型を渡すと勝手に展開してくれるので便利だ
using Dapper;
using System.Data.SQLite;
using System.Diagnostics;

// プロジェクト直下の同クラスと同じ階層にDBを格納
string ConnectionString = @"Data Source=../../../test.db;";

// SQLiteDB接続
using (var connection = new SQLiteConnection(ConnectionString))
{
    // DBオープン
    connection.Open();

    // トランザクションを開始(今回は未使用)
    using (var tarn = connection.BeginTransaction())
    {
        // SQL文
        string sql = "SELECT * FROM Person WHERE Id IN @Id";
        
        // Dynamic Object作成(IN句の場合)
        var condtion = new
        {
            Id = new List<int>() { 1, 3 }
        };

        // Dapperで検索
        var result = connection.Query<PersonDto>(sql, condtion);

        // 検索結果を確認
        foreach (var person in result)
        {
            Debug.Print(person.ToString());
        }
    }

    // DBクローズ
    connection.Close();
}

5.3. 動作確認

image.png

6. サンプルコード(動的Where句)

6.1. DBアクセスクラス(抜粋)

using Dapper;
using System.Data.SQLite;
using System.Diagnostics;

// プロジェクト直下の同クラスと同じ階層にDBを格納
string ConnectionString = @"Data Source=../../../test.db;";

// SQLiteDB接続
using (var connection = new SQLiteConnection(ConnectionString))
{
    // DBオープン
    connection.Open();

    // トランザクションを開始(今回は未使用)
    using (var tarn = connection.BeginTransaction())
    {
        // SQL文
        string sql = @"SELECT * FROM Person WHERE (@Id IS NULL OR @Id = '' OR Id = @Id)";
        
        // Dynamic Object作成
        var condtion = new
        {
            Id = ""
        };

        // Dapperで検索
        var result = connection.Query<PersonDto>(sql, condtion);

        // 検索結果を確認
        foreach (var person in result)
        {
            Debug.Print(person.ToString());
        }
    }

    // DBクローズ
    connection.Close();
}

6.2. 動作確認

  • Dynamic Objectの変数がNULLまたは空白の場合、Where条件対象から外すことができる
    image.png

7. サンプルコード(動的Where句かつIN句)

7.1. 問題点

  • 上記と同様な考え方でコードを記述するとエラーが発生する
  • 実行後のSQLをよく見るとIN句のDynamic Objectの変数が展開されて、@Id1,@Id2...になって元の@Idがなくなっている
    image.png
    image.png

7.2. 今回対応した方法

  • 動的Where句のIN句の条件対象を判定するDynamic Objectの変数を追加する
  • SQLで追加した変数で条件を判定するように変更する
// SQL文
string sql = @"SELECT * FROM Person WHERE (@Id_IsWhere IS NULL OR @Id_IsWhere = '' OR Id IN @Id)";

// Dynamic Object作成
    var condtion = new
    {
        // IN句がある場合
        Id = new List<int>() { 1, 3 },
        Id_IsWhere = "Add"
        // IN句がない場合
        // Id = null
     };

     // Dapperで検索
     var result = connection.Query<PersonDto>(sql, condtion);

8. 参考文献

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?