C#/Mono から Npgsql を使って PostgreSQL に接続してみる

C#/Mono から Npgsql を使って PostgreSQL に接続するプログラムの作成方法について説明します。

環境は CentOS 7 または 8、PostgreSQL 9.6 以降を対象とし、PostgreSQL に接続できる状態になっていることを前提とします。PostgreSQL のインストールや設定がまだであれば、インストール方法は [こちらの記事](https://qiita.com/tom-sato/items/e1903cb974fb6c6d5664)、ローカルホスト以外からの接続受けつけに必要な設定方法は [こちらの記事](https://qiita.com/tom-sato/items/d5f722fd02ed76db5440) を参照してください。

1. Mono、NuGet をインストールします。

    Mono リポジトリを登録します。

    ```shell-session
    $ curl -s https://download.mono-project.com/repo/centos8-stable.repo | sudo tee /etc/yum.repos.d/mono-centos8-stable.repo
    [mono-centos8-stable]
    name=mono-centos8-stable
    baseurl=https://download.mono-project.com/repo/centos8-stable/
    enabled=1
    gpgcheck=1
    gpgkey=https://download.mono-project.com/repo/xamarin.gpg
    ```

    コマンドラインに含まれる 2 箇所の `centos8` は CentOS 8 を表します。CentOS 7 の場合は `centos7` に書き替えてください。

    続いて、Mono、NuGet をインストールします。

    ```shell-session
    $ sudo yum install -y mono-complete nuget
    (省略)
    Complete!
    ```

    EPEL リポジトリでも Mono、NuGet をインストールできますが、NuGet をアップデートしても .NET 用パッケージがインストールできなかったので、Mono リポジトリを使ったほうがよいでしょう。

1. Npgsql をインストールします。

    ```shell-session
    $ mkdir TestNpgsql
    $ cd TestNpgsql
    $ nuget install Npgsql -Version 4.1.9
    (省略)
    Successfully installed 'Npgsql 4.1.9' to /home/vagrant/TestNpgsql
    Executing nuget actions took 4.45 sec
    ```

    Npgsql とその依存パッケージはカレントディレクトリにインストールされるので、ここでは `TestNpgsql` ディレクトリを作成し、移動した上でインストールしています。また、Npgsql のバージョンは最新だと Mono が対応していないようなので、バージョン 4.1 系列の最新バージョン、ここでは 4.1.9 をインストールしています。Npgsql のバージョン情報は [こちらのページ](https://www.nuget.org/packages/Npgsql/) を参照してください。

1. プログラムを作成します。

    プログラムの内容はデータベースの一覧を出力するというものです。エラー処理は行っていません。

    ```c#:TestNpgsql.cs
    using System;
    using Npgsql;
    
    class TestNpgsql
    {
        static void Main()
        {
            var connString = "Host=localhost;Port=5432;Database=postgres;Username=postgres;Password=password";
            using (var conn = new NpgsqlConnection(connString))
            using (var cmd = new NpgsqlCommand("SELECT datname FROM pg_database", conn))
            {
                conn.Open();
                using (var reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        Console.WriteLine(reader.GetString(0));
                    }
                }
            }
        }
    }
    ```

    変数 `connString` には `;` 区切りで `パラメータ名=値` 形式で接続先を指定します。パラメータの `Host` は接続先のホスト、`Port` はポート、`Database` はデータベース、`Username` はユーザ名、`Password` はパスワードを表します。ご自身の環境に合わせて書き替えてください。

1. プログラムをビルドします。

    ```shell-session
    $ mcs -r:Npgsql.4.1.9/lib/net461/Npgsql.dll,System.Data.dll TestNpgsql.cs
    ```

    `-r` オプションにはカンマ `,` 区切りでメタデータを読み込むアセンブリのパスを指定します。Npgsql のパスはご自身の環境に合わせて書き替えてください。

    エラーメッセージが出力されず、実行ファイル `TestNpgsql.exe` が生成されれば、プログラムのビルドは成功です。

1. プログラムを実行します。

    ```shell-session
    $ MONO_PATH=$(ls -d */lib/netstandard2.0 | paste -d : -s) mono TestNpgsql.exe
    postgres
    template1
    template0
    ```

    環境変数 `MONO_PATH` にはコロン `:` 区切りでアセンブリ格納先のパスを指定します。ここではコマンド置換でカレントディレクトリ内の `lib/netstandard2.0` ディレクトリを含むディレクトリを指定しています。

    エラーメッセージが出力されず、データベースの一覧が出力されれば、プログラムの実行は成功です。

以上でプログラムの作成は完了です。C#/Mono については詳しくないので、コメントがあればよろしくお願いします。