rksoftware

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

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

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

■ DB 直繋ぎ

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

■ ゴール

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

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

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

・コードビハインド

using System.Collections.Generic;
using System.Data;
using Xamarin.Forms;

namespace XFDataTable
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

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

            listView.BindingContext = dt;
        }
    }
}

・XAML

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XFDataTable"
             x:Class="XFDataTable.MainPage">
    <ListView x:Name="listView" ItemsSource="{Binding}" >
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout Orientation="Horizontal">
                        <Label Text="{Binding ID}"/>
                        <Label Text=", "/>
                        <Label Text="{Binding Name}"/>
                        <Label Text=", "/>
                        <Label Text="{Binding Description}"/>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>

■ NuGet パッケージの追加

この状態で実行すると、実行時にエラーが発生します。
f:id:rksoftware:20180902192457j:plain
エラーメッセージからは分かりませんが、対策は System.Data.SqlClient NugGet パッケージをインストールすることです。
NuGet パッケージを追加し、再度実行します。

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

この状態で実行すると、次のように画面表示されます。
f:id:rksoftware:20180902193230j:plain
データバインディングされていません。デスクトップアプリ開発では DataTable で値を扱い DataGrid へバインディングした経験のある方も多いと思います。しかし残念ながら Xamarin.Forms の ListView は DataTable の値をバインディングできないようです。
対策として、ビューへのバインディング用のクラスを作ることにします(DataRowWrapper クラス)。

・コードビハインド

using System.Collections.Generic;
using System.Data;
using Xamarin.Forms;

namespace XFDataTable
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

            var dt = new DataTable();
            using (var con = new System.Data.SqlClient.SqlConnection(
                "User ID = *****; Password = *****; Initial Catalog = *****; 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 row in dt.Rows)
                list.Add(new DataRowWrapper(row));

            listView.BindingContext = 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:20180902193151j:plain
これで、モバイルアプリから DB に直接接続してデータを扱い放題です。
※実際に扱う機会があるかは別として。