LoginSignup
0
0

More than 1 year has passed since last update.

Xamarinアプリケーション開発に、NoSQLドキュメント指向組み込みデータベースCouchbase Liteを使ってみる

Last updated at Posted at 2021-12-21

はじめに

本稿では、NoSQLドキュメント指向組み込みデータベースCouchbase Liteを使ったXamarinアプリケーションを紹介します。

Couchbase Liteをアプリケーション開発に利用する意義については、以下の記事をご参考ください。

下記の記事で、Couchbase LiteをC#アプリケーション開発で利用するためのセットアップと動作確認のプロセスを紹介しました。

本稿では、Couchbase Labsで公開されているサンプルアプリケーションソースコードを使って、Xamarinアプリケーション開発にCouchbase Liteを使う方法を、具体的なコードによって解説します。

本稿の内容は、以下のチュートリアルの内容に基づきます。

ここでは扱っていませんが、Couchbase Liteをモバイルアプリ開発に利用する利点として、Couchbase Serverとの双方向データ同期が可能なことがあります。Couchbase Serverについては、日本語で読むことができるまとまった情報として、次の拙著を紹介させていただきます。

サンプルアプリケーション解説

今回紹介するアプリケーションは、XamarinでCouchbase Lite 2.xを(Couchbase Serverと同期せずに)「スタンドアローン」で利用するものとなっています。

アプリケーションは、Xamarin.Forms、C#、XAML(Extensible Application Markup Language)を使用しています。

iOS、Android、およびUWP用のコードが提供されています。

前提条件

  • iOS(Xcode 10以降)
  • Android(SDK 21+)
  • UWP(Windows 10)

アプリケーション仕様

ユーザープロファイル情報管理機能を実装したアプリケーション(Couchbase Liteの機能利用方法の説明に特化された、非常に簡易なものとなっています)。

ユーザーは、アプリ内で管理されているアカウント情報を使用して、アプリにログインします。
ログイン後、そのユーザーのプロファイル情報が表示され、編集することができます。
新規登録の場合も、ログイン画面にて情報したユーザーが未登録の場合は新規ユーザーとして追加され、入力した情報を引き継がれたプロファイル画面に遷移後、追加の情報を入力します。

プロファイル情報は、アプリ内のローカルデータベースであるCouchbase Liteに保存されます。

アプリケーション操作イメージを以下示します。

image.png

セットアップ

GitHubからソリューションのstandaloneブランチをクローンします。

git clone -b standalone https://github.com/couchbaselabs/userprofile-couchbase-mobile-xamarin.git

リポジトリの/modules/userprofile/examples/srcの下に、ソリューションファイルUserProfileDemo.slnが存在します。

ソリューション構造

ソリューションは、7つのプロジェクトで構成されています。

  • UserProfileDemo:ビューレベルの機能を担当する.NET標準プロジェクト。
  • UserProfileDemo.Core:ビューモデルレベルの機能を担当する.NET標準プロジェクト。
  • UserProfileDemo.Models:単純なデータモデルで構成される.NET標準プロジェクト。
  • UserProfileDemo.Repositories:Couchbase Liteデータベースの初期化および管理などを担当するリポジトリクラスで構成される.NET標準プロジェクト。
  • UserProfileDemo.iOS:iOSプラットフォームプロジェクト。.ipaファイルのビルドを担当する
  • UserProfileDemo.Android:Androidプラットフォームプロジェクト。.apkファイルのビルドを担当する
  • UserProfileDemo.UWP:UWPプラットフォームプロジェクト。.exeファイルのビルドを担当する

このソリューションでは、MVVM、IoC、リポジトリパターンなどの、さまざまなデザインパターンと原則が利用されています。

Couchbase Liteパッケージ

ソリューションにおけるCouchbase Liteの依存関係について解説します。
Couchbase.Lite Nugetパッケージは、このソリューションの4つのプロジェクト内で参照として含まれています。

  • UserProfileDemo.Repositories
  • UserProfileDemo.iOS
  • UserProfileDemo.Android
  • UserProfileDemo.UWP

以下は、UserProfileDemo.Repositoriesにおける定義の例です。

UserProfileDemo.Repositories.csproj
    <PackageReference Include="Couchbase.Lite" Version="2.6.0" />

Couchbase.Liteパッケージには、Couchbaseの Liteのコア機能が含まれています。これは、Couchbase Liteのコミュニティエディションにあたります。商業利用用のパッケージとして別にCouchbase.Lite.Enterpriseがあります。

コードによる解説

データモデル

Couchbase LiteはJSONドキュメントストアです。JSONドキュメントの論理構造は、名前付きフィールドと値のコレクションです。値は有効なJSONタイプです。標準のJSONタイプに加えて、Couchbase LiteはBlobおよびDateデータタイプをサポートしています。

このアプリケーションでは、ドキュメントの種類を特定するために、「type」プロパティを用います。これは必須ではありませんが、一つのCouchbase Liteデータベースに複数のデータモデルが混在する構成の場合の典型的な設計です。

このアプリは、「type」プロパティとして「user」の値を持つドキュメントを処理します。
また、ドキュメントIDの形式は「user::<email>」となっています。

ユーザープロファイルJSONデータ

ユーザープロファイル情報を表現するJSONドキュメントの例は次のようになります

{
    "type":"user",
    "name":"Jane Doe",
    "email":"jane.doe@earth.org",
    "address":"101 Main Street",
    "image":CBLBlob (image/jpg) 
}

image」プロパティは、プロファイル画像格納に用いられるBLOB型データを値として利用します。

ユーザープロファイルクラス

上述のデータモデルに対応するクラスとして、以下のようなUserProfileクラスを用います。

これは、ProfileDemo.Modelsプロジェクトに含まれます。

public class UserProfile
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Address { get; set; }
    public byte[] ImageData { get; set; }
    public string Description { get; set; }
}

Couchbase Liteアクティブ化

Xamarinアプリ内でCouchbase Liteを使用するには、Couchbase.Lite Nugetパッケージをプラットフォームごとにアクティブ化します。

iOS

AppDelegate.cs
Couchbase.Lite.Support.iOS.Activate();

Android

MainActivity.cs
Couchbase.Lite.Support.Droid.Activate(this);

UWP

MainPage.xaml.cs
Couchbase.Lite.Support.UWP.Activate();

データベース操作

データベース作成/オープン

ユーザーがアプリにログインすると、データベースが存在しない場合、空のCouchbase Liteデータベースが作成されます。

BaseRepository.csファイルを開き、Databaseプロパティを確認します。

BaseRepository.cs
Database _database;
protected Database Database
{
    get
    {
        if (_database == null)
        {
            _database = new Database(DatabaseName, DatabaseConfig);
        }

        return _database;
    }
    private set => _database = value;
}

ここでは、DatabaseConfigurationのインスタンスを作成する際に、データベースのデフォルトパスを上書きしています。すべてのユーザーが、そのユーザーに対応するフォルダーの下に自身のデータベースを持つことになります(要件的には、1ユーザー=1プロファイルとなるデータを格納するためには冗長に思われますが、ここでは機能の説明のためと理解してください)。

UserProfileRepository.cs
DatabaseConfiguration _databaseConfig;
protected override DatabaseConfiguration DatabaseConfig
{
    get
    {
        if (_databaseConfig == null)
        {
            if (AppInstance.User?.Username == null)
            {
                throw new Exception($"Repository Exception: A valid user is required!");
            }

            _databaseConfig = new DatabaseConfiguration
            {
                Directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                                AppInstance.User.Username)
            };
        }

        return _databaseConfig;
    }
    set => _databaseConfig = value;
}

データベース変更イベントの活用

Couchbase Liteデータベースにリスナーを登録することによって、データベースの変更(追加、削除、更新)を非同期的に通知できます。

このアプリではデータベースへの変更をログに記録する以外のことは行っていません。より現実的なアプリでは、たとえばこの通知を使用してUIを更新します。

BaseRepository.csファイルを開き、Database.AddChangeListenerコンストラクター内で関数の使用法を確認します。

リスナーをデータベースに登録するには、デリゲートメソッドOnDatabaseChangeEventを追加します。AddChangeListenerメソッドは、ListenerTokenを返します。ListenerTokenは、データベースからリスナーを削除するために必要とされます。

BaseRepository.cs
DatabaseListenerToken = Database.AddChangeListener(OnDatabaseChangeEvent);

上記で引数として利用されている、OnDatabaseChangeEventの定義は、以下のようなものです。

BaseRepository.cs
void OnDatabaseChangeEvent(object sender, DatabaseChangedEventArgs e)
{
    foreach (var documentId in e.DocumentIDs)
    {
        var document = Database?.GetDocument(documentId);

        string message = $"Document (id={documentId}) was ";

        if (document == null)
        {
            message += "deleted";
        }
        else
        {
            message += "added/updaAted";
        }

        Console.WriteLine(message);
    }
}

データベースのクローズ

ユーザーがログアウトすると、ユーザーに関連付けられているCouchbase Liteデータベースをクローズし、リスナーの登録を解除し、メモリ割り当てを解放します。

BaseRepository.csファイルを開き、Disposeメソッドを確認します。
このメソッドは、データベースリスナーの削除、メモリからのさまざまなオブジェクトの削除、およびデータベースのクローズを処理します。 Disposeメソッドは、ユーザーがログアウトすると呼び出されます。

BaseRepository.cs
public void Dispose()
{
    DatabaseConfig = null;

    Database.RemoveChangeListener(DatabaseListenerToken);
    Database.Close();
    Database = null;
}

ドキュメント操作

ドキュメント読み込み

ユーザーがログインすると、ユーザープロファイル画面が表示されます。この時、内部的に、そのユーザーの「ユーザープロファイル」ドキュメントが読み込まれます。
ユーザーが初めてログインするとき、ユーザーのユーザープロファイルドキュメントはありません。

UserProfileViewModel.csファイルを開き、userProfileDocId定義を確認します。このドキュメントIDは、ユーザーのユーザー名の前に「user::」という接頭辞を付けることで作成されます。

UserProfileViewModel.cs
string UserProfileDocId => $"user::{AppInstance.User.Username}";

UserProfileViewModelは、ログインしているユーザーのプロファイルを取得する役割を持ちます。ユーザーのプロファイル情報取得は、IUserProfileRepositoryを実装するクラスを使用して行われます。

UserProfileViewModel.cs
var up = UserProfileRepository?.Get(UserProfileDocId);

UserProfileRepository.csのGetメソッドを確認します。

UserProfileRepository.cs
public override UserProfile Get(string userProfileId)

データベースから指定されたuserProfileIdをキーに持つドキュメントを取得します。

UserProfileRepository.cs
var document = Database.GetDocument(userProfileId);

if (document != null)
{
    userProfile = new UserProfile
    {
        Id = document.Id,
        Name = document.GetString("Name"),
        Email = document.GetString("Email"),
        Address = document.GetString("Address"),
        ImageData = document.GetBlob("ImageData")?.Content
    };
}

データベースからドキュメントを取得した上で、その値を用いてUserProfileクラスのインスタンスを作成します。

ここでは、ドキュメントのメンバーをフェッチするために、いくつかの方法が使用されています。特に、Blobタイプのプロパティの値をフェッチするためのGetBlobメソッドのサポートに注意してください。

ドキュメント作成/更新

「ユーザープロファイル」ドキュメントは、ユーザーが「プロファイル画面」の「完了」ボタンをタップすると更新または新規作成(初回実行時)されます。

UserProfileViewModelは、データベースに設定されたプロファイルの値を保存する役割を担います。これは、IUserProfileRepositoryを実装するクラスを使用して行います。

UserProfileViewModel.cs
bool? success = UserProfileRepository?.Save(userProfile);

UserProfileRepository.csファイルを開き、Save関数を確認します。

UserProfileRepository.cs
public override bool Save(UserProfile userProfile)

ここれは、Documentのミュータブル(可変)インスタンスを作成します。

デフォルトでは、Couchbase LiteのすべてのAPIはイミュータブル(非可変)オブジェクトを扱い、設計上、スレッドセーフになっています。

オブジェクトを変更するには、オブジェクトの変更可能なコピーを明示的に取得する必要があります。適切なセッターメソッドを使用して、Documentのさまざまなプロパティを設定します。Blobタイプのプロパティ用にSetBlobメソッドが利用されます。

UserProfileRepository.cs
var mutableDocument = new MutableDocument(userProfile.Id);
mutableDocument.SetString("Name", userProfile.Name);
mutableDocument.SetString("Email", userProfile.Email);
mutableDocument.SetString("Address", userProfile.Address);
mutableDocument.SetString("type", "user");
if (userProfile.ImageData != null)
{
    mutableDocument.SetBlob("ImageData", new Blob("image/jpeg", userProfile.ImageData));
}

ドキュメント保存

Database.Save(mutableDocument);

ドキュメント削除

このサンプルアプリでは、ドキュメントを削除していません。
以下のコードは、ドキュメント削除する場合のコード例です。

var document = Database.GetDocument(id);

if (document != null)
{
    Database.Delete(document);
}

動作確認

アプリ実行とログイン

アプリを実行します。

任意のユーザー名とパスワードでアプリにログインします。ここでは、ユーザー名とパスワードのフィールドにそれぞれ「demo@example.com」と「password」という値を使用します。

ログ確認(iOS)

コンソールログの出力に次のようなメッセージが表示されていることを確認します。この例では、「demo@example.com」というユーザー名でログインしています。

Will open/create DB  at path Will open/create DB  at path /Users/[user_name]/Library/Developer/CoreSimulator/Devices/[unique_device_id]/data/Containers/Data/Application/[unique_app_id]/Library/Application Support/demo@example.com

データベースファイル確認

上記のログメッセージは、ユーザーのデータベースの場所を示しています。

Finderでフォルダを開き、「userprofile.cblite2」という名前のデータベースがユーザーに存在することを確認します

image.png

最後に

本稿では、iOS、Android、またはUWPアプリでローカルのみのスタンドアロンの埋め込みデータストアとしてCouchbase Liteを利用するアプリケーションのサンプルを紹介しました。

Xamarinアプリケーション開発に組み込みデータベースを使った経験のある方であれば、以降の応用は、比較的簡単に可能かと思います。
最後に、次のステップに進むための情報を示して、本稿の締め括りとしたいと思います。

Couchbase Liteについての記事を以下の投稿で整理していますので、ご関心に応じて、参照してみてください。

公式ドキュメントは、以下になります。

今回の記事の一次参考情報は、以下のチュートリアルです。

上記チュートリアルの発展として、データベースに対するクエリを扱ったものがあります。

また、さらに、Couchbase Serverとのデータ同期を扱ったものもあります。

他にも、公式ドキュメントの一部として、各種チュートリアルが公開されています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0