記事一覧

SQLite データベースを使用してデータ保存する | Xamarin.Forms


ローカルデータベースを利用したXamarin.Formsの開発方法についてご紹介いたします。SQLiteというお手軽データベースがNuGetパッケージにて公開されています。今回はSQLiteを用いてデータベースへの入出力ができるところまで検証していきたいと思います。



前提条件
・Windows10
・Visual Studio 2015 Community Update3
・Xamarin 4.3.0.784 (NuGet Xamarin.Forms 2.3.4.224)
・macOS Sierra 10.12.4 / Xcode8.3.1 / Xamarin.iOS 10.4.0.123



1.SQLiteのインストール

NuGetパケージマネージャにてSQLiteを検索します。
"sqlite-net-pcl"で検索します。同じようなパッケージが多く、識別が難しいです。私がインストールしたのは、以下に明記されているパッケージです。
バージョン 1.4.118
作成者:Frank A. Krueger
公開日:2017/07/28
※旧バージョンの SQLite.Net-PCL 3.1.1 をインストールするとAndroid7.0以降でエラーが表示されますので、お気を付けください。エラーの内容については次の記事「Android7.0以降でSQLiteを実行すると表示されるエラーメッセージの対応方法」をご覧ください。

xamarin_sqlite_02.png

※PCLを含めた全てのプロジェクトにインストールします。



2.DependencyServiceの記述

PCL
using SQLite;
public interface ISQLService
{
    SQLiteConnection GetConnection();
}

Android
using SQLite;
[assembly: Dependency(typeof(SQLService))]
public class SQLService : ISQLService
{
    public SQLiteConnection GetConnection()
    {
        var personalPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
        var path = System.IO.Path.Combine(personalPath, "MyDatabaseName");
        return new SQLiteConnection(path);
    }
}

iOS
using SQLite;
[assembly: Dependency(typeof(SQLService))]
public class SQLService : ISQLService
{
    public SQLiteConnection GetConnection()
    {
        var personalPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
        var libraryPath = System.IO.Path.Combine(personalPath, "..", "Library");
        var path = System.IO.Path.Combine(libraryPath, "MyDatabaseName");
        return new SQLiteConnection(path);
    }
}



3.DB操作

(1)モデルクラスを作成する。
CustomerInfo.cs
using SQLite;
public class CustomerInfo
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }
    public string Name { get; set; }
    public bool IsDeleted { get; set; }
    public CustomerInfo()
    {
this.IsDeleted = false;
    }
}

(2)DBへの接続を保持し、SQLを発行するクラスを作成する
DbUtility.cs
using SQLite;
public class DbUtility
{
    static SQLiteConnection _con;
public bool IsInTransaction { get { return _con.IsInTransaction; } }

    public DbUtility()
    {
        //コネクションを取得
        _con = DependencyService.Get<ISQLService>().GetConnection();
        //テーブルを更新する (何度流しても良い)
        _con.CreateTable<CustomerInfo>();
    }

//トランザクションを開始する
public void BeginTran()
{
while (_con.IsInTransaction)
{ //他のトランザクションが終了するまで待機する
}
_con.BeginTransaction();
}
public void RollBack()
{
if (this.IsInTransaction)
{
_con.Rollback();
}
}
public void Commit()
{
_con.Commit();
}

    /// <summary>
    /// 顧客リストを取得する
    /// </summary>
    /// <returns></returns>
    public ObservableCollection<CustomerInfo> GetCustomerInfoList()
    {
        IEnumerable<CustomerInfo> cInfo = _con.Table<CustomerInfo>().Where(m => m.IsDeleted == false);
        //IEnumerable<T>型からObservableCollection<T>型に変換
        return new ObservableCollection<CustomerInfo>(cInfo)
    }

    /// <summary>
    /// 顧客情報を取得する
    /// </summary>
    /// <returns></returns>
    public CustomerInfo GetCustomerInfo(int id)
    {
        return _con.Table<CustomerInfo>().Where(m => m.Id == id &&
                                                        m.IsDeleted == false).SingleOrDefault();
    }

    /// <summary>
    /// 顧客情報を更新する
    /// </summary>
    /// <param name="cInfo">顧客情報</param>
    /// <returns></returns>
    public int UpdateCustomerInfo(CustomerInfo cInfo)
    {
        int cnt = 0;
        if (cInfo.Id != 0)
        {
            //Idが0でない場合は更新
            cnt = _con.Update(cInfo);
        }
        else
        {
           //Id=0の場合は新規でInsert
            cnt = _con.Insert(cInfo);
        }
        return cnt;
    }

    /// <summary>
    /// 顧客情報を削除する
    /// </summary>
    /// <param name="cInfo">顧客情報</param>
    /// <returns></returns>
    public int DeleteCustomerInfo(CustomerInfo cInfo)
    {
        int cnt = 0;
        if (cInfo.Id != 0)
        {
            //Idが0でない場合、削除可能
            cnt = _con.Delete(cInfo);
        }
        return cnt;
    }
    /// <summary>
    /// 顧客情報を削除する
    /// </summary>
    /// <param name="id">ID</param>
    /// <returns></returns>
    public int DeleteCustomerInfo(int id)
    {
        CustomerInfo cInfo = this.GetCustomerInfo(id);
        return this.DeleteCustomerInfo(cInfo);
    }
}

CreatTableは現在のクラスの構造と比較して列が追加されている場合、自動的にテーブルに列を追加してくれます。追加された列の値はNULLとなります。
ただし、キーの変更や型の変更等には対応していませんので、もしも間違えた型を含むクラスでCreateTable<T>() してしまったら、一度DropTable<T>() しましょう。



4.使用方法

インスタンス化を行い、メンバメソッドをコールします。
DbUtility dbUtil = new DbUtility();
//出力
this.ListView1.ItemsSource = dbUtil.GetCustomerInfoList();
//入力
var cInfo = dbUtil.GetCustomerInfo(1);
cInfo.Name = "test";
dbUtil.BeginTran();
try
{
if (dbUtil.UpdateCustomerInfo(cInfo) > 0)
{
dbUtil.Commit();
await DisplayAlert("登録", "保存しました。", "OK");
}
else
{
dbUtil.RollBack();
await DisplayAlert("登録", "登録できませんでした。", "OK");
}
}
catch (Exception ex)
{
dbUtil.RollBack();
}



5.注意点

(1)登録できるデータ型に制限はなさそうです。
  型として登録できたもの(検証した限りです。)
  ・String型
  ・int型
  ・DateTime型 ※UTCで換算されますので、日付がずれます。
  ・DateTimeOffset型  ※日付型はこちらを使用しましょう
  ・byte[]型
  ・Enum列挙型

(2)モデルクラスには必ず引数なしのコンストラクタを用意しましょう。引数がないコンストラクタが無い場合は以下のようなエラーが発生します。
System.MissingMethodException  Constructor on type ’TypeName’ not found.

(3)コネクションを保持する変数はstaticにしてどこから呼ばれても唯一のインスタンスになるようにシングルトンパターンで実装しましょう。
複数のコネクションからの処理を行うと、SQLiteDatabaseLockedExceptionが発生し、「Busy」「DataBase is locked」とエラーが出力されます。

(4)DBを更新する場合は明示的にトランザクションを開始・終了しましょう。
明示的に開始・終了しない場合は、自動的に開始されるようですが、複数の更新処理を正しく制御できない場合、SQLiteDatabaseLockedExceptionが発生し、「Busy」「DataBase is locked」とエラーが出力されます。

(5)非同期で実行したい場合は、NuGetパッケージの「SQLite.Net.Async-PCL」をインストールしましょう。Asyncのメソッドが実装されています。

(6)複数スレッドでの並列処理を行う場合はコネクションの作成方法を変更しなければなりません。以下のURLにてご紹介しております。
http://itblogdsi.blog.fc2.com/blog-entry-192.html



当ブログの内容をまとめた Xamarin逆引きメニュー は以下のURLからご覧になれます。
http://itblogdsi.blog.fc2.com/blog-entry-81.html


関連記事

コメント

コメントの投稿

広告

プロフィール

石河 純


著者名 :石河 純
自己紹介:素人上がりのIT技術者。趣味は卓球・車・ボウリング

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語・データベース】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
Oracle10g SQLServer2008R2 SQLAnywhere8/11/16
ActiveReport CrystalReport ReportNet(IBM)
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS IIS6/7 apache2

休みの日は卓球をやっています。
現在、卓球用品通販ショップは休業中です。