【WPF】SQLite から Linq でデータを取得してDataGrid に表示してみる
おはようございます。
今日も引き続き WPF@C#の話しです。
その他リソースの外部ファイル化をやろうかと思ったのですが、
DataGridにちゃんとデータベースからデータを表示したかったのでちょっと寄り道。
とりあえずサンプルなんかで無料のデータベースを使うのあれば SQLite で十分なので、
SQLiteを使ってデータの検索、DataGridへの表示をやってみようと思います。
プログラムは前回のものを修正します。
まずは SQLite に接続するための準備から。
スポンサーリンク
Nuget でパッケージをダウンロード
ソリューションエクスプローラーからプロジェクトを選択、右クリックし
「Nuget パッケージの管理」を選択します。
Nuget パッケージ管理画面が表示されるので、
検索窓に「SQLite」を入力し、「System.Data.SQLite」を選択、
インストールボタンをクリックします。
変更の確認ダイアログが表示されるので、
「OK」ボタンをクリックします。
出力ビューに「終了」が出力されればOKです。
ソリューションエクスプローラーの「参照」を開き
System.Data.* が追加されていることが確認できれば追加完了です。
ビルド
一度ビルドを実行します。
上部メニューの「ビルド」>「ソリューションのリビルド」を選択します。
プロジェクトのディレクトリ>bin>Target>x86 、x64 に「SQLite.Interop.dll」が
出力されていることを確認します。
起動時にテーブルを作成する
プログラム修正
アプリケーション起動時に、テーブルを作成するようにプログラムを修正します。
MainWindows.xaml.cs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    // SQLite利用のため追加
    using System.Data.SQLite;
    
    namespace WpfApp1
    {
        /// <summary>
        /// MainWindow.xaml の相互作用ロジック
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                // SampleDb.sqlite を作成(存在しなければ)
                using (var conn = new SQLiteConnection("Data Source=SampleDb.sqlite"))
                {
                    // データベースに接続
                    conn.Open();
                    // コマンドの実行
                    using (var command = conn.CreateCommand())
                    {
                        // テーブルが存在しなければ作成する
                        // 種別マスタ
                        StringBuilder sb = new StringBuilder();
                        sb.Append("CREATE TABLE IF NOT EXISTS MSTKIND (");
                        sb.Append("  KIND_CD NCHAR NOT NULL");
                        sb.Append("  , KIND_NAME NVARCHAR");
                        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 INT NOT NULL");
                        sb.Append("  , NAME NVARCHAR NOT NULL");
                        sb.Append("  , SEX NVARCHAR NOT NULL");
                        sb.Append("  , AGE INT DEFAULT 0 NOT NULL");
                        sb.Append("  , KIND_CD NCHAR DEFAULT 0 NOT NULL");
                        sb.Append("  , FAVORITE NVARCHAR");
                        sb.Append("  , primary key (NO)");
                        sb.Append(")");
    
                        command.CommandText = sb.ToString();
                        command.ExecuteNonQuery();
    
                    }
                    // 切断
                    conn.Close();
                }
            }
        }
    }
アプリケーションの実行
上部メニューの開始ボタンをクリックし、アプリケーションを実行すると
「MSTKIND」、「TBLCAT」テーブルが作成されます。
SQLite のデータベースを操作できるツール等で、テーブルが作成されていることを確認します。
今回は Firefox のアドオン「SQLite Manager」で確認しました。
データの追加
次のデータをツール、もしくはコマンドラインから追加します。
    INSERT INTO MSTKIND VALUES ("01", "キジトラ");
    INSERT INTO MSTKIND VALUES ("02", "長毛種(不明)");
    INSERT INTO MSTKIND VALUES ("03", "ミケ(っぽい)");
    INSERT INTO MSTKIND VALUES ("04", "サビ");
    INSERT INTO MSTKIND VALUES ("09", "その他");
    INSERT INTO TBLCAT VALUES('1','そら','♂','6','01','犬の人形');
    INSERT INTO TBLCAT VALUES('2','りく','♂','5','02','人間');
    INSERT INTO TBLCAT VALUES('3','うみ','♀','4','03','高級ウェットフード');
    INSERT INTO TBLCAT VALUES('4','こうめ','♀','2','04','横取りフード');
今度はコマンドラインから追加してみました。
更に SQLite Manager にて確認。
Linq で データを取得、設定する
Linqとは
オブジェクトやデータベース、データセット、エンティティ、XML文書など、アプリケーションで扱うさまざまなデータソースに対して、統一的な手段でアクセスするしくみ
Linq用パッケージの追加
Linqを利用するため、ライブラリの追加を行います。
ソリューションエクスプローラに表示されている「参照」を右クリックし
参照の追加画面を開きます。
「System.Data.Linq」を検索し、表示されたものを選択、「OK」ボタンをクリックします。
プログラム修正
クラス追加
種別クラス
Kind.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Linq.Mapping;
namespace WpfApp1
{
    [Table(Name = "mstkind")]
    public class Kind
    {
        [Column(Name = "kind_cd", IsPrimaryKey = true)]
        public String KindCd { get; set; }
        [Column(Name = "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.Data.Linq.Mapping;
namespace WpfApp1
{
    [Table(Name = "tblcat")]
    public class Cat
    {
        [Column(Name = "no", IsPrimaryKey = true)]
        public int No { get; set; }
        [Column(Name = "name")]
        public String Name { get; set; }
        [Column(Name = "sex")]
        public String Sex { get; set; }
        [Column(Name = "age")]
        public int Age { get; set; }
        [Column(Name = "kind_cd")]
        public String Kind { get; set; }
        [Column(Name = "favorite")]
        public String Favorite { get; set; }
    }
}
宣言の追加
MainWindow.xaml.cs
Linqを利用するためにパッケージ利用宣言を追加
(System.Data.Linq.Mapping)
省略
.
.
using System.Data.SQLite; 
using System.Data.Linq; // ←を追記する
using System.Data.Linq.Mapping; // ←を追記する
namespace WpfApp1 {
省略
}データ取得処理の追加
「MainWindow」メソッドに次の記述を追加
MainWindow.xaml.cs
                    // 種別マスタを取得してコンボボックスに設定する
                    using (DataContext con = new DataContext(conn))
                    {
                        // データを取得
                        Table<Kind> mstKind = con.GetTable<Kind>();
                        IQueryable<Kind> result = from x in mstKind orderby x.KindCd select x;
    
                        // 最初の要素は「指定なし」とする
                        Kind empty = new Kind();
                        empty.KindCd = "";
                        empty.KindName = "指定なし";
                        var list = result.ToList();
                        list.Insert(0, empty);
    
                        // コンボボックスに設定
                        this.search_kind.ItemsSource = list;
                        this.search_kind.DisplayMemberPath = "KindName";
                    }
新規メソッドの追加(クリックイベント)
            /// <summary>
            /// 検索ボタンクリックイベント.
            /// 
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void search_button_Click(object sender, RoutedEventArgs e)
            {
                using (var conn = new SQLiteConnection("Data Source=SampleDb.sqlite"))
                {
                    conn.Open();
    
                    // 猫データ一覧を取得して DataGrid に設定
                    using (DataContext con = new DataContext(conn))
                    {
                        String searchName = this.search_name.Text;
                        String searchKind = (this.search_kind.SelectedValue as Kind).KindCd;
    
                        // データを取得
                        Table<Cat> tblCat = con.GetTable<Cat>();
    
                        // サンプルなので適当に組み立てる
                        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();
                    }
    
                    conn.Close();
                }
    
            }ビューの修正
検索ボタンにクリックイベントを追加します。
MainWindows.xaml
    <Button x:Name="search_button" Content="検索" Margin="432,12,0,0" Style="{StaticResource btn-normal}" Click="search_button_Click"/>起動
全件検索
全データが表示されました。
名前指定検索
名前を指定したので、そらのみ表示されました。
種別指定検索
みけっぽい、「うみ」のみ表示されました。
存在しない組み合わせで検索
こうめはサビなので、なにも表示されません。
まとめ
ひとまず、DataGrid に表示できました。
サンプルなのでソースはまあまあ適当ですが、なんとなく使い方がわかってきました。
(実は Linq も初)
日々新しい技術が出てくるのでついていくのが大変ですね。
頑張ります。
次回(未定)は Log4net を使ってみたいと思います。
ではでは。
ソースはこちら
ディスカッション
コメント一覧
今更ながらWPFの勉強の為にサイトにお邪魔してます。
ここ2~3にちこのページで止まってしまっています。
コピペが基本なのですが、エラーになってしまいどうしたらいいのか解からない状態です。
解決方法を教えて頂けたらと思います。
私の拙い記事を参考にしていただきありがとうございます。
どういった状況なのかコメントからわかりませんでしたので、
よろしければ下記の内容をメールでいただけますか。(わかる範囲で結構です)
1. OS
2. VisualStudio のバージョン
3. どの部分でエラーが発生するのか(ビルド時、その他)
4. エラーメッセージ
メールアドレス:doraxdora.gm.biz@gmail.com
よろしくお願いします。
C#初心者です。大変参考にさせていただいております。質問ですが、VS2017でコードをコピーして開始すると「’Kind’がありません」のエラーが出てしまいます。Kindクラスの設定が必要ですか?
Ken様
いつも記事を見ていただきありがとうございます。
ご指摘の件、
一部記事に不足がありましたので修正しました。
コメントありがとうございます。
また、GitHubにソースも上げましたのでよろしければご参照ください。
今後ともよろしくお願い致します。
ありがとうございます。しかし、gitをクリックしても、git にたどり着けません。リンクをご確認していただけませんでしょうか?
Ken様
失礼しました。
リンクURLを修正しましたのでご確認ください。
よろしくお願いします。
WPFについて勉強したくページにたどり着きました。
丁寧な記事ありがとうございます。
最初、コードを写しても動かなかったため以下を修正して動きました。
VS2017です。
# MainWindow.xaml.cs 宣言に以下を追加
using System.Data.Linq;
# MainWindow.xaml 下記を変更
ComboBox x:Name=”search_type”
→ComboBox x:Name=”search_kind”
quan 様
いつも記事を見ていただきありがとうございます。
ご指摘の件、ありがとうございます。
見直してみたところ、確かに前回の記事では「search_type」となっており
そのまま記事の通り修正すると動作しませんでした。スミマセン。
以前の記事(https://www.doraxdora.com/blog/2017/06/08/post-1155/)と合わせて、プログラムを修正致しました。
今後ともよろしくお願い致します。
似たようなものを作りたく、参考にさせて頂いてます。
newとかの後のスペースが見れないのは私だけでしょうか?
コピペしても、そのあたりのスペースが無い為自分でつけてます。
たろこ様
ブログを見ていただきありがとうございます。
ご質問の件ですが、
すみません、コード表示用のプラグインの不備化と思います。
コード部分をダブルクリックすると表示が変わると思いますのでお試しください。
今後ともよろしくお願い致します。
回答ありがとうございます!
ダブルクリックしたら正しく表示されました。
お手数をおかけしました。
質問なのですが、classファイルを作成するときに
[Table(Name = “tblcat”)]とつけているのは何か理由があるのでしょうか?
また、SQLiteのtableを別途作成しておき
その値をComboboxの選択肢にしたいのですが、
探してもいい方法が見当たらないのです…。
どうやったらSQLiteの特定Tableの値をComboboxに参照出来るのでしょうか?
ここで聞くべきでは無いと思いつつも、手詰まりとなっておりまして
お手数ですがアドバイス等頂ければと思いますorz
たろこ様
コードが正しく表示されたようでよかったです。
ご質問の件、
Classについているコードですが、
Entity Framework のアノテーションとなります。
データベース(SQLite)のテーブルと、クラスおよびフィールドをマップするために指定しているものですね。
詳細はご自身でお調べ頂ければと思います。
コンボボックスの件についても、記事内で MstKind テーブルからデータを表示しているのを参考にしていただければと思います。
今後ともよろしくお願い致します。