tag:crieit.net,2005:https://crieit.net/tags/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/tags/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','そら','♂','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','横取りフード');
</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) & 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