rksoftware

Visual Studio とか C# とかが好きです

UWP で SQL Server と直接接続し DataTable で値を扱う

.NET Standard 2.0 では SQL Server と直接接続し、DataTable で値を扱えます。
これは、.NET Core と .NET Framework のどちらでも使えるライブラリで扱える、というところまでは便利になったなという感覚です。
しかし .NET Standard 2.0 はそれだけでは収まりません。なんと UWP でも使えてしまうのです。

■ 禁断の DB 直繋ぎ

UWP によるアプリで SQL Server に直繋ぎができてしまいます。すごい。
※推奨されません。というか通常はやるべきではありません。

■ ゴール

SQL Server 上に TestTable というテーブルを作成し次の様にデータを用意します。
f:id:rksoftware:20180909193923j:plain
この DB に UWP アプリで接続し、次の様に画面表示します。
f:id:rksoftware:20180909193939j:plain

■ プロジェクトの新規作成

Visual Studio で UWP プロジェクトを新規作成します。
新規作成のテンプレートで 空白のアプリ (ユニバーサル Windows) を選択します。
f:id:rksoftware:20180909194212j:plain
WPF や Xamarin.Forms アプリの場合の WPF アプリ (.NET Framework)モバイル アプリ (Xamarin.Forms) と少し表現が違って迷いますが自信をもって選択しましょう。

最小プラットフォームのバージョンを選択

ここが一番大事な部分です。
プロジェクトテンプレートを選択し [OK] を押すと、プラットフォームバージョンの選択がダイアログが表示されます。
ここで 最小バージョンWindows 10 Fall Creators Update (10.0; ビルド 16299) 以上を選択します。こうしないと、.NET Standard 2.0 が使えません。
f:id:rksoftware:20180909194246j:plain
参考

もし間違えて作成してしまった場合
プロジェクトのプロパティの アプリケーション > ターゲット で変更でします。安心してください。

■ NuGet パッケージの追加は不要

Xamarin で SQL Server と直接接続する場合は System.Data.SqlClient NuGet パッケージの追加が必要でしたが、UWP では不要です。
参考

■ コード(まだうまくいかない)

ひとまず素直にコードを書いてみます。伝統的作法で SQL 文を記述して実行します。
・コードビハインド

using System.Collections.Generic;
using System.Data;
using Windows.UI.Xaml.Controls;

namespace UWPApp1
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            var dt = new DataTable();
            using (var con = new System.Data.SqlClient.SqlConnection(
                "User ID = XXXXX; Password = XXXXX; Initial Catalog = TestDB; Server = (local)"))
            using (var cmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM TestTable", con))
            {
                con.Open();
                dt.Load(cmd.ExecuteReader());
            }
    
            this.DataContext = dt;
        }
    }
}

・XAML

<Page
    x:Class="UWPApp1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UWPApp1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>
        <ListBox ItemsSource="{Binding}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="|"/>
                        <TextBlock Text="{Binding ID}"/>
                        <TextBlock Text=", "/>
                        <TextBlock Text="{Binding Name}"/>
                        <TextBlock Text=", "/>
                        <TextBlock Text="{Binding Description}"/>
                        <TextBlock Text="|"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
                
        </ListBox>
    </Grid>
</Page>

■ DataBinding 用のモデルクラスの作成

この状態で実行すると、次のように画面表示されます。
f:id:rksoftware:20180909194308j:plain

データバインディングされていません。デスクトップアプリ開発では DataTable で値を扱いビューへバインディングした経験のある方も多いと思います。しかし残念ながら UWP の ListBox は DataTable の値をバインディングできないようです。
対策として、ビューへのバインディング用のクラスを作ることにします(DataRowWrapper クラス)。

・コードビハインド

using System.Collections.Generic;
using System.Data;
using Windows.UI.Xaml.Controls;

namespace UWPApp1
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            var dt = new DataTable();
            using (var con = new System.Data.SqlClient.SqlConnection(
                "User ID = XXXXX; Password = XXXXX; Initial Catalog = TestDB; Server = (local)"))
            using (var cmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM TestTable", con))
            {
                con.Open();
                dt.Load(cmd.ExecuteReader());
            }

            var list = new List<DataRowWrapper>();
            foreach (DataRow dr in dt.Rows)
                list.Add(new DataRowWrapper(dr));

            this.DataContext = list;
        }
    }

    public class DataRowWrapper
    {
        DataRow _row;
        public DataRowWrapper(DataRow row) => _row = row;
        public int ID => (int)_row[nameof(ID)];
        public string Name => (string)_row[nameof(Name)];
        public string Description => (string)_row[nameof(Description)];
    }
}

■ 実行

この状態で実行すると見事値が画面表示されます。
f:id:rksoftware:20180909193939j:plain
これで、UWP アプリから DB に直接接続してデータを扱い放題です。
※実際に扱う機会があるかは別として。