【WPF】PostgreSQL に接続してデータを取得して表示する

公開日:2019-06-25
最終更新:2019-06-25
※この記事は外部サイト(https://www.doraxdora.com/blog/2017/08/08/...)からのクロス投稿です

今回は、PostgreSQLを使ってデータを検索、データグリッドに表示してみます。
お決まりですが、プログラムは前回までのものを流用します。

【WPF】ProgressRingを使って時間のかかる処理を分かりやすくする

また、PostgreSQLをインストールしていない場合は次の記事を参照して、パソコンにインストールしてください。

PostgreSQL 9.6.3 をインストールしてテーブルを作成する

Nuget でパッケージをダウンロード

NuGetパッケージ管理を開く[/caption]

ソリューションエクスプローラーからプロジェクトを選択、右クリックし
「Nuget パッケージの管理」を選択

NuGetパッケージ管理[/caption]

Nuget パッケージ管理画面が表示されるので、
検索窓に「Npgsql 6」を入力し、「EntityFramework6.Npgsql」を選択、
インストールボタンをクリックします。

プレビュー画面が表示される場合は「OK」ボタンをクリックします。

出力ビューに「終了」が表示されれば完了です。

スキーマの作成

PostgreSQL ではスキーマ単位の管理をしておかないと困ることになります。

スキーマ指定しないでテーブル作成すると「public」スキーマに作成されるのですが、
C#からの接続時には必ず(やってみた限りでは)スキーマ指定しないといけないので、まずはスキーマを作成しておきます。

CREATE SCHEMA dora;  

テーブルの作成

作成したスキーマににテーブルを作成
SQLite の時と同じテーブル、データを用意します。

このとき、テーブル名やカラム名は小文字にしておくこと。

CREATE TABLE IF NOT EXISTS dora.mstkind (  
        kind_cd CHAR(2) NOT NULL  
        , kind_name VARCHAR(20)  
        , primary key (kind_cd)  
);  


CREATE TABLE IF NOT EXISTS dora.tblcat (  
        no INTEGER NOT NULL  
        , name VARCHAR(20) NOT NULL  
        , sex CHAR(3) NOT NULL  
        , age INTEGER DEFAULT 0 NOT NULL  
        , kind_cd CHAR(2) DEFAULT '00' NOT NULL  
        , favorite VARCHAR(40)  
        , PRIMARY KEY (no)  
);  

INSERT INTO DORA.MSTKIND VALUES ('01', 'キジトラ');  
INSERT INTO DORA.MSTKIND VALUES ('02', '長毛種(不明)');  
INSERT INTO DORA.MSTKIND VALUES ('03', 'ミケ(っぽい)');  
INSERT INTO DORA.MSTKIND VALUES ('04', 'サビ');  
INSERT INTO DORA.MSTKIND VALUES ('09', 'その他');  
INSERT INTO DORA.TBLCAT VALUES('1','そら','♂','6','01','犬の人形');  
INSERT INTO DORA.TBLCAT VALUES('2','りく','♂','5','02','人間');  
INSERT INTO DORA.TBLCAT VALUES('3','うみ','♀','4','03','高級ウェットフード');  
INSERT INTO DORA.TBLCAT VALUES('4','こうめ','♀','2','04','横取りフード');  

設定ファイルの修正

次のようにします。
重要な部分は、「entityFramework」タグと「system.data」タグ。

App.config

<?xml version="1.0" encoding="utf-8"?>  
<configuration>  
  <configSections>  
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->  
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />  
  </configSections>  
  <startup>  
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />  
  </startup>  
  <entityFramework>  
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">  
      <parameters>  
        <parameter value="v13.0" />  
      </parameters>  
    </defaultConnectionFactory>  
    <providers>  
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />  
      <provider invariantName="Npgsql" type="Npgsql.NpgsqlServices, EntityFramework6.Npgsql" />  
    </providers>  
  </entityFramework>  
  <system.data>  
    <DbProviderFactories>  
      <remove invariant="Npgsql" />  
      <add name="Npgsql Data Provider" invariant="Npgsql" support="FF" description=".Net Framework Data Provider for Postgresql" type="Npgsql.NpgsqlFactory, Npgsql" />  
    </DbProviderFactories>  
</system.data>  
  <runtime>  
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">  
      <dependentAssembly>  
        <assemblyIdentity name="Npgsql" publicKeyToken="5d8b90d52f46fda7" culture="neutral" />  
        <bindingRedirect oldVersion="0.0.0.0-3.2.5.0" newVersion="3.2.5.0" />  
      </dependentAssembly>  
    </assemblyBinding>  
  </runtime>  
</configuration>  

プログラム修正

新規クラスの追加

DbContextを継承したクラスを作成します。
このクラスでデータベースへの接続、Entityへのマッピングなどを行います。
デフォルトのスキーマを変更する場合、「OnModelCreating」メソッドにて設定可能です。

PgDbContext.cs

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.Threading.Tasks;  

using System.Data.Entity;  
using Npgsql;  

namespace WpfApp1  
{  
    class PgDbContext : DbContext  
    {  
        private const string ConnectionString = "Server=localhost;User ID=USER01;Password=USER01;Database=DB01;port=5432";  

        // コンストラクタにて接続文字列を設定  
        public PgDbContext() : base(new NpgsqlConnection(ConnectionString), true) { }  

        public DbSet<Kind> Kinds { get; set; }  
        public DbSet<Cat> Cats { get; set; }  

        // スキーマを変更する場合にはここに設定  
        protected override void OnModelCreating(DbModelBuilder modelBuilder)  
        {  
            //Configure default schema  
            modelBuilder.HasDefaultSchema("dora");  
        }  
    }  
}  

Entityクラスの修正

アノテーションが今までのとちょっと違うので修正します。

Kind.cs

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.Threading.Tasks;  

using System.ComponentModel.DataAnnotations;  
using System.ComponentModel.DataAnnotations.Schema;  

namespace WpfApp1  
{  
    [Table("mstkind")]  
    class Kind  
    {  
        [Key]  
        [Column("kind_cd")]  
        public String KindCd { get; set; }  
        [Column("kind_name")]  
        public String KindName { get; set; }  
    }  
}  

Cat.cs

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.Threading.Tasks;  

using System.ComponentModel.DataAnnotations;  
using System.ComponentModel.DataAnnotations.Schema;  

namespace WpfApp1  
{  
    [Table("tblcat")]  
    class Cat  
    {  
        [Key]  
        [DatabaseGenerated(DatabaseGeneratedOption.None)]  
        [Column("no")]  
        public int No { get; set; }  
        [Column("name")]  
        public String Name { get; set; }  
        [Column("sex")]  
        public String Sex { get; set; }  
        [Column("age")]  
        public int Age { get; set; }  
        [Column("kind_cd")]  
        public String Kind { get; set; }  
        [Column("favorite")]  
        public String Favorite { get; set; }  
    }  
}  

宣言の追加

MainWindow.xaml.cs

using Npgsql;  
using System.ComponentModel;  

接続処理の変更

テーブル作成以外、全ての箇所を変更します。

MainWindow.xaml.cs

//using (var conn = new SQLiteConnection("Data Source=SampleDb.sqlite"))  
using (var context = new PgDbContext())  

テーブル作成は今まで通りコマンドで行います。
(また別途、DbContext でのやり方は紹介します)

テーブル作成クエリの変更

SQLite とは微妙に違うところ(型、長さ)を変更。

MainWindow.xaml.cs

// テーブルが存在しなければ作成する  
// 種別マスタ  
StringBuilder sb = new StringBuilder();  
sb.Append("CREATE TABLE IF NOT EXISTS mstkind (");  
sb.Append(" kind_cd CHAR(2) NOT NULL");  
sb.Append(" , kind_name VARCHAR(20)");  
sb.Append(" , PRIMARY KEY (kind_cd)");  
sb.Append(")");  
command.CommandText = sb.ToString();  
command.ExecuteNonQuery();  

// 猫テーブル  
sb.Clear();  
sb.Append("CREATE TABLE IF NOT EXISTS tblcat (");  
sb.Append(" no INTEGER NOT NULL");  
sb.Append(" , name VARCHAR(20) NOT NULL");  
sb.Append(" , sex CHAR(3) NOT NULL");  
sb.Append(" , age INTEGER DEFAULT 0 NOT NULL");  
sb.Append(" , kind_cd CHAR(2) DEFAULT '00' NOT NULL");  
sb.Append(" , favorite VARCHAR(40)");  
sb.Append(" , PRIMARY KEY (no)");  
sb.Append(")");  

command.CommandText = sb.ToString();  
command.ExecuteNonQuery();  

検索処理の修正

MainWindow.xaml.cs

        /// <summary>  
        /// 検索処理(非同期)  
        /// </summary>  
        /// <param name="sender"></param>  
        /// <param name="e"></param>  
        private void SearchProcess(object sender, DoWorkEventArgs e)  
        {  
            // 猫データマスタを取得してコンボボックスに設定する  
            //using (var conn = new SQLiteConnection("Data Source=SampleDb.sqlite"))  
            // PgDbContext に変更  
            using (var context = new PgDbContext())  
            {  
                String searchName = this.search_name.Text;  
                String searchKind = (this.search_kind.SelectedValue as Kind).KindCd;  

                // データを取得  
                // context から DbSet を取得  
                //Table<Cat> tblCat = con.GetTable<Cat>();  
                var tblCat = context.Cats;  

                // サンプルなので適当に組み立てる  
                IQueryable<Cat> result;  
                if (searchKind == "")  
                {  
                    // 名前は前方一致のため常に条件していしても問題なし  
                    result = from x in tblCat  
                             where x.Name.StartsWith(searchName)  
                             orderby x.No  
                             select x;  
                }  
                else  
                {  
                    result = from x in tblCat  
                             where x.Name.StartsWith(searchName) &amp; x.Kind == searchKind  
                             orderby x.No  
                             select x;  

                }  
                this.dataGrid.ItemsSource = result.ToList();  
            }  
        }  

コンバーターの修正

データグリッドに表示する際に値を変換している箇所も、DB接続しているため変更します。

KindConverter.cs

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.Threading.Tasks;  

using System.Data.Linq;  
using System.Data.SQLite;  
using System.Data.SQLite.Linq;  

// Converter 用  
// IValueConverter、CultureInfo  
using System.Windows.Data;  
using System.Globalization;  


namespace WpfApp1  
{  
    /// <summary>  
    /// 種別コンバータークラス.  
    /// </summary>  
    public class KindConverter : IValueConverter  
    {  
        /// <summary>  
        /// データ変換処理  
        /// </summary>  
        /// <param name="value"></param>  
        /// <param name="targetType"></param>  
        /// <param name="parameter"></param>  
        /// <param name="culture"></param>  
        /// <returns></returns>  
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)  
        {  
            //using (var conn = new SQLiteConnection("Data Source=SampleDb.sqlite"))  
            // PgDbContext に変更  
            using (var context = new PgDbContext())  
            {  
                // データを取得  
                //Table<Kind> tblCat = con.GetTable<Kind>();  
                //Kind k = tblCat.Single(c => c.KindCd == value as String);  
                var kind = context.Kinds.SingleOrDefault(c => c.KindCd == (String)value);  
                if (kind != null)  
                {  
                    return kind.KindName;  
                }  
                return "";  
            }  
        }  

        /// <summary>  
        /// データ復元処理  
        /// </summary>  
        /// <param name="value"></param>  
        /// <param name="targetType"></param>  
        /// <param name="parameter"></param>  
        /// <param name="culture"></param>  
        /// <returns></returns>  
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)  
        {  
            using (var context = new PgDbContext())  
            {  
                // データを取得  
                //Table<Kind> tblCat = con.GetTable<Kind>();  
                //Kind k = tblCat.Single(c => c.KindCd == value as String);  
                var kind = context.Kinds.SingleOrDefault(c => c.KindName == value as String);  
                if (kind != null)  
                {  
                    return kind.KindCd;  
                }  

            }  
            return "";  
        }  
    }  
}  

起動してみる

無事に起動、検索することができました。

まとめ

ひとまず、元々の処理(SQLite、MySQL)とあまり変更せずに実装することができました。

ちょっと長くなってしまったので、
登録、更新、削除はまた次回とさせていただきます。

ではでは。

記事が少しでもいいなと思ったらクラップを送ってみよう!
0
+1
@doraxdoraの技術ブログ 主に Java, C#, Python, Javascript の記事を載せていく予定。

よく一緒に読まれている記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
目次をみる

技術ブログをはじめよう

Qrunch(クランチ)は、ITエンジニアリングに携わる全ての人のための技術ブログプラットフォームです。

技術ブログを開設する

Qrunchでアウトプットをはじめよう

Qrunch(クランチ)は、ITエンジニアリングに携わる全ての人のための技術ブログプラットフォームです。

Markdownで書ける

ログ機能でアウトプットを加速

デザインのカスタマイズが可能

技術ブログ開設

ここから先はアカウント(ブログ)開設が必要です

英数字4文字以上
.qrunch.io
英数字6文字以上
ログインする