tag:crieit.net,2005:https://crieit.net/magazines/doraxdorax/WPF%E3%81%A7PostgreSQL%E3%82%92%E4%BD%BF%E3%81%86/feed WPFでPostgreSQLを使うの投稿 - Crieit Crieitで連載「WPFでPostgreSQLを使う」の最近の投稿 2019-06-26T09:51:09+09:00 https://crieit.net/magazines/doraxdorax/WPF%E3%81%A7PostgreSQL%E3%82%92%E4%BD%BF%E3%81%86/feed tag:crieit.net,2005:PublicArticle/15168 2019-06-26T09:51:09+09:00 2019-06-26T09:51:09+09:00 https://crieit.net/posts/WPF-PostgreSQL-5d12c17d61f60 【WPF】PostgreSQL に接続してデータを操作(登録、更新、削除)してみる <p>おはようございます。</p> <p>前回に引き続き PostgreSQL を使って、登録、更新、削除をしてみたいと思います。</p> <p>前回の記事はこちら。<br /> <a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2017/08/08/post-1948/" target="_blank" rel="noopener noreferrer" data-blogcard="1">【WPF】PostgreSQL に接続してデータを取得して表示する</a></p> <h2 id="プログラムの修正"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E4%BF%AE%E6%AD%A3">プログラムの修正</a></h2> <h3 id="追加処理の修正"><a href="#%E8%BF%BD%E5%8A%A0%E5%87%A6%E7%90%86%E3%81%AE%E4%BF%AE%E6%AD%A3">追加処理の修正</a></h3> <p>MainWindow.xaml.cs</p> <pre><code> /// <summary> /// 追加ボタンクリックイベント /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void add_button_Click(object sender, RoutedEventArgs e) { logger.Info("追加ボタンクリック"); // データを追加する // PgDbContext に変更 //using (var conn = new SQLiteConnection("Data Source=SampleDb.sqlite")) using (var context = new PgDbContext()) { // データ作成 // テーブルはコンテキスト経由でアクセスする //var table = context.GetTable<Cat>(); Cat cat = new Cat(); cat.No = 5; cat.No = 5; cat.Name = "こなつ"; cat.Sex = "♀"; cat.Age = 7; cat.Kind = "01"; cat.Favorite = "布団"; // データ追加 // コンテキスト経由でエンティティを追加 //table.InsertOnSubmit(cat); context.Cats.Add(cat); // DBの変更を確定 // メソッド変更 //context.SubmitChanges(); context.SaveChanges(); } // データ再検索 searchData(); MessageBox.Show("データを追加しました。"); } </code></pre> <h3 id="更新処理"><a href="#%E6%9B%B4%E6%96%B0%E5%87%A6%E7%90%86">更新処理</a></h3> <p>MainWindow.xaml.cs</p> <pre><code> /// <summary> /// 更新ボタンクリックイベント /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void upd_button_Click(object sender, RoutedEventArgs e) { logger.Info("更新ボタンクリック"); // 選択チェック if (this.dataGrid.SelectedItem == null) { MessageBox.Show("更新対象を選択してください。"); return; } // データを更新する // PgDbContext に変更 //using (var conn = new SQLiteConnection("Data Source=SampleDb.sqlite")) using (var context = new PgDbContext()) { // 対象のテーブルオブジェクトを取得 // テーブルはコンテキスト経由でアクセスする //var table = context.GetTable<Cat>(); var table = context.Cats; // 選択されているデータを取得 Cat cat = this.dataGrid.SelectedItem as Cat; // テーブルから対象のデータを取得 var target = table.Single(x => x.No == cat.No); // データ変更 target.Favorite = "高いところ"; // DBの変更を確定 // メソッド変更 //context.SubmitChanges(); context.SaveChanges(); } // データ再検索 searchData(); MessageBox.Show("データを更新しました。"); } </code></pre> <p> </p> <h3 id="削除処理"><a href="#%E5%89%8A%E9%99%A4%E5%87%A6%E7%90%86">削除処理</a></h3> <p>MainWindow.xaml.cs</p> <pre><code> /// <summary> /// 削除ボタンクリックイベント /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void del_button_Click(object sender, RoutedEventArgs e) { logger.Info("追加ボタンクリック"); // 選択チェック if (this.dataGrid.SelectedItem == null) { MessageBox.Show("削除対象を選択してください。"); return; } // データを削除する // PgDbContext に変更 //using (var conn = new SQLiteConnection("Data Source=SampleDb.sqlite")) using (var context = new PgDbContext()) { // 対象のテーブルオブジェクトを取得 // テーブルはコンテキスト経由でアクセスする //var table = context.GetTable<Cat>(); var table = context.Cats; // 選択されているデータを取得 Cat cat = this.dataGrid.SelectedItem as Cat; // テーブルから対象のデータを取得 var target = table.Single(x => x.No == cat.No); // データ削除 // メソッド変更 //table.DeleteOnSubmit(target); table.Remove(target); // DBの変更を確定 context.SaveChanges(); } // データ再検索 searchData(); MessageBox.Show("データを削除しました。"); } </code></pre> <p> </p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>サクッとした記事になりましたが、ひとまず PostgreSQL はここまでとして次回は Oracle を試してみたいと思います。</p> <p>ソースはこちら</p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/doraxdora/SampleWpfPostgreSQL1" target="_blank" rel="noopener noreferrer">GitHub</a></p> <p>ではでは。</p> doraxdora tag:crieit.net,2005:PublicArticle/15166 2019-06-25T10:05:02+09:00 2019-06-25T10:05:02+09:00 https://crieit.net/posts/WPF-PostgreSQL 【WPF】PostgreSQL に接続してデータを取得して表示する <p>おはようございます。</p> <p>今回は、PostgreSQLを使ってデータを検索、データグリッドに表示してみます。<br /> お決まりですが、プログラムは前回までのものを流用します。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2017/07/28/post-1873/" target="_blank" rel="noopener" data-blogcard="1">【WPF】ProgressRingを使って時間のかかる処理を分かりやすくする</a></p> <p>また、PostgreSQLをインストールしていない場合は次の記事を参照して、パソコンにインストールしてください。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2017/07/25/post-1748/" target="_blank" rel="noopener" data-blogcard="1">PostgreSQL 9.6.3 をインストールしてテーブルを作成する</a></p> <h2 id="Nuget でパッケージをダウンロード"><a href="#Nuget+%E3%81%A7%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%82%92%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89">Nuget でパッケージをダウンロード</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/08/WpfPostgreSQL000.jpg" alt="NuGetパッケージ管理を開く" /></p> <p>ソリューションエクスプローラーからプロジェクトを選択、右クリックし<br /> 「Nuget パッケージの管理」を選択</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/08/WpfPostgreSQL001.jpg" alt="NuGetパッケージ管理" /></p> <p>Nuget パッケージ管理画面が表示されるので、<br /> 検索窓に「Npgsql 6」を入力し、「EntityFramework6.Npgsql」を選択、<br /> インストールボタンをクリックします。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/08/WpfPostgreSQL002.jpg" alt="プレビュー画面" /></p> <p>プレビュー画面が表示される場合は「OK」ボタンをクリックします。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/08/WpfPostgreSQL003.jpg" alt="出力ビュー" /></p> <p>出力ビューに「終了」が表示されれば完了です。</p> <h2 id="スキーマの作成"><a href="#%E3%82%B9%E3%82%AD%E3%83%BC%E3%83%9E%E3%81%AE%E4%BD%9C%E6%88%90">スキーマの作成</a></h2> <p>PostgreSQL ではスキーマ単位の管理をしておかないと困ることになります。</p> <p>スキーマ指定しないでテーブル作成すると「public」スキーマに作成されるのですが、<br /> C#からの接続時には必ず(やってみた限りでは)スキーマ指定しないといけないので、まずはスキーマを作成しておきます。</p> <pre><code>CREATE SCHEMA dora; </code></pre> <h2 id="テーブルの作成"><a href="#%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90">テーブルの作成</a></h2> <p>作成したスキーマににテーブルを作成<br /> SQLite の時と同じテーブル、データを用意します。</p> <p>このとき、テーブル名やカラム名は小文字にしておくこと。</p> <pre><code>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','そら','&#x2642;','6','01','犬の人形'); INSERT INTO DORA.TBLCAT VALUES('2','りく','&#x2642;','5','02','人間'); INSERT INTO DORA.TBLCAT VALUES('3','うみ','&#x2640;','4','03','高級ウェットフード'); INSERT INTO DORA.TBLCAT VALUES('4','こうめ','&#x2640;','2','04','横取りフード'); </code></pre> <h2 id="設定ファイルの修正"><a href="#%E8%A8%AD%E5%AE%9A%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%BF%AE%E6%AD%A3">設定ファイルの修正</a></h2> <p>次のようにします。<br /> 重要な部分は、「entityFramework」タグと「system.data」タグ。</p> <p>App.config</p> <pre><code><?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> </code></pre> <h2 id="プログラム修正"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E4%BF%AE%E6%AD%A3">プログラム修正</a></h2> <h3 id="新規クラスの追加"><a href="#%E6%96%B0%E8%A6%8F%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E8%BF%BD%E5%8A%A0">新規クラスの追加</a></h3> <p>DbContextを継承したクラスを作成します。<br /> このクラスでデータベースへの接続、Entityへのマッピングなどを行います。<br /> デフォルトのスキーマを変更する場合、「OnModelCreating」メソッドにて設定可能です。</p> <p>PgDbContext.cs</p> <pre><code>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"); } } } </code></pre> <h3 id="Entityクラスの修正"><a href="#Entity%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E4%BF%AE%E6%AD%A3">Entityクラスの修正</a></h3> <p>アノテーションが今までのとちょっと違うので修正します。</p> <p>Kind.cs</p> <pre><code>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; } } } </code></pre> <p>Cat.cs</p> <pre><code>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; } } } </code></pre> <h3 id="宣言の追加"><a href="#%E5%AE%A3%E8%A8%80%E3%81%AE%E8%BF%BD%E5%8A%A0">宣言の追加</a></h3> <p>MainWindow.xaml.cs</p> <pre><code>using Npgsql; using System.ComponentModel; </code></pre> <h3 id="接続処理の変更"><a href="#%E6%8E%A5%E7%B6%9A%E5%87%A6%E7%90%86%E3%81%AE%E5%A4%89%E6%9B%B4">接続処理の変更</a></h3> <p>テーブル作成以外、全ての箇所を変更します。</p> <p>MainWindow.xaml.cs</p> <pre><code>//using (var conn = new SQLiteConnection("Data Source=SampleDb.sqlite")) using (var context = new PgDbContext()) </code></pre> <p>テーブル作成は今まで通りコマンドで行います。<br /> (また別途、DbContext でのやり方は紹介します)</p> <h3 id="テーブル作成クエリの変更"><a href="#%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E4%BD%9C%E6%88%90%E3%82%AF%E3%82%A8%E3%83%AA%E3%81%AE%E5%A4%89%E6%9B%B4">テーブル作成クエリの変更</a></h3> <p>SQLite とは微妙に違うところ(型、長さ)を変更。</p> <p>MainWindow.xaml.cs</p> <pre><code>// テーブルが存在しなければ作成する // 種別マスタ 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(); </code></pre> <h3 id="検索処理の修正"><a href="#%E6%A4%9C%E7%B4%A2%E5%87%A6%E7%90%86%E3%81%AE%E4%BF%AE%E6%AD%A3">検索処理の修正</a></h3> <p>MainWindow.xaml.cs</p> <pre><code> /// <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(); } } </code></pre> <h3 id="コンバーターの修正"><a href="#%E3%82%B3%E3%83%B3%E3%83%90%E3%83%BC%E3%82%BF%E3%83%BC%E3%81%AE%E4%BF%AE%E6%AD%A3">コンバーターの修正</a></h3> <p>データグリッドに表示する際に値を変換している箇所も、DB接続しているため変更します。</p> <p>KindConverter.cs</p> <pre><code>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 ""; } } } </code></pre> <p> </p> <h2 id="起動してみる"><a href="#%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">起動してみる</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/08/WpfPostgreSQL004.jpg" alt="検索結果" /></p> <p>無事に起動、検索することができました。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>ひとまず、元々の処理(SQLite、MySQL)とあまり変更せずに実装することができました。</p> <p>ちょっと長くなってしまったので、<br /> 登録、更新、削除はまた次回とさせていただきます。</p> <p>ではでは。</p> <p> </p> doraxdora