はじめに
本稿では、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に保存されます。
アプリケーション操作イメージを以下示します。
セットアップ
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における定義の例です。
<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
Couchbase.Lite.Support.iOS.Activate();
Android
Couchbase.Lite.Support.Droid.Activate(this);
UWP
Couchbase.Lite.Support.UWP.Activate();
データベース操作
データベース作成/オープン
ユーザーがアプリにログインすると、データベースが存在しない場合、空のCouchbase Liteデータベースが作成されます。
BaseRepository.csファイルを開き、Database
プロパティを確認します。
Database _database;
protected Database Database
{
get
{
if (_database == null)
{
_database = new Database(DatabaseName, DatabaseConfig);
}
return _database;
}
private set => _database = value;
}
ここでは、DatabaseConfiguration
のインスタンスを作成する際に、データベースのデフォルトパスを上書きしています。すべてのユーザーが、そのユーザーに対応するフォルダーの下に自身のデータベースを持つことになります(要件的には、1ユーザー=1プロファイルとなるデータを格納するためには冗長に思われますが、ここでは機能の説明のためと理解してください)。
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
は、データベースからリスナーを削除するために必要とされます。
DatabaseListenerToken = Database.AddChangeListener(OnDatabaseChangeEvent);
上記で引数として利用されている、OnDatabaseChangeEvent
の定義は、以下のようなものです。
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
メソッドは、ユーザーがログアウトすると呼び出されます。
public void Dispose()
{
DatabaseConfig = null;
Database.RemoveChangeListener(DatabaseListenerToken);
Database.Close();
Database = null;
}
ドキュメント操作
ドキュメント読み込み
ユーザーがログインすると、ユーザープロファイル画面が表示されます。この時、内部的に、そのユーザーの「ユーザープロファイル」ドキュメントが読み込まれます。
ユーザーが初めてログインするとき、ユーザーのユーザープロファイルドキュメントはありません。
UserProfileViewModel.csファイルを開き、userProfileDocId
定義を確認します。このドキュメントIDは、ユーザーのユーザー名の前に「user::」という接頭辞を付けることで作成されます。
string UserProfileDocId => $"user::{AppInstance.User.Username}";
UserProfileViewModel
は、ログインしているユーザーのプロファイルを取得する役割を持ちます。ユーザーのプロファイル情報取得は、IUserProfileRepository
を実装するクラスを使用して行われます。
var up = UserProfileRepository?.Get(UserProfileDocId);
UserProfileRepository.csのGet
メソッドを確認します。
public override UserProfile Get(string userProfileId)
データベースから指定されたuserProfileId
をキーに持つドキュメントを取得します。
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
を実装するクラスを使用して行います。
bool? success = UserProfileRepository?.Save(userProfile);
UserProfileRepository.csファイルを開き、Save
関数を確認します。
public override bool Save(UserProfile userProfile)
ここれは、Document
のミュータブル(可変)インスタンスを作成します。
デフォルトでは、Couchbase LiteのすべてのAPIはイミュータブル(非可変)オブジェクトを扱い、設計上、スレッドセーフになっています。
オブジェクトを変更するには、オブジェクトの変更可能なコピーを明示的に取得する必要があります。適切なセッターメソッドを使用して、Document
のさまざまなプロパティを設定します。Blobタイプのプロパティ用にSetBlob
メソッドが利用されます。
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」という名前のデータベースがユーザーに存在することを確認します
最後に
本稿では、iOS、Android、またはUWPアプリでローカルのみのスタンドアロンの埋め込みデータストアとしてCouchbase Liteを利用するアプリケーションのサンプルを紹介しました。
Xamarinアプリケーション開発に組み込みデータベースを使った経験のある方であれば、以降の応用は、比較的簡単に可能かと思います。
最後に、次のステップに進むための情報を示して、本稿の締め括りとしたいと思います。
Couchbase Liteについての記事を以下の投稿で整理していますので、ご関心に応じて、参照してみてください。
公式ドキュメントは、以下になります。
今回の記事の一次参考情報は、以下のチュートリアルです。
上記チュートリアルの発展として、データベースに対するクエリを扱ったものがあります。
また、さらに、Couchbase Serverとのデータ同期を扱ったものもあります。
他にも、公式ドキュメントの一部として、各種チュートリアルが公開されています。