Windows Phone のローカル データベースの概要

2012/02/09

Windows Phone OS 7.1 では、アプリケーションの分離ストレージ コンテナー内に存在するローカル データベースにリレーショナル データを格納できます。Windows Phone アプリケーションはすべてのデータベース操作に LINQ to SQL を使用します。LINQ to SQL は、データベース スキーマを定義し、データを選択し、分離ストレージ内に存在する基になるデータベース ファイルに変更を保存するのに使用されます。ここでは、Windows Phone アプリケーションでのローカル データベースの使用の概要について説明します。ローカル データベースを使用するアプリケーションを作成する手順については、「方法: Windows Phone 用の基本的なローカル データベース アプリケーションを作成する」を参照してください。

ローカル データベースでデータの格納および取得を行うには、Windows Phone アプリケーションで LINQ to SQL を使用します。LINQ to SQL は、オブジェクト指向式のデータの操作を可能にするもので、オブジェクト モデルとランタイムで構成されます。

LINQ to SQL オブジェクト モデルは主に、ローカル データベースのプロキシとして機能する System.Data.Linq.DataContext オブジェクトによって構成されます。LINQ to SQL ランタイムは、データ (ローカル データベース) の世界とオブジェクト (DataContext オブジェクト) の世界を橋渡しする役割を担っています。この関係は、次の図のようにまとめることができます。

Windows Phone DataContext およびローカル データベース

データ コンテキストはデータベースを表すオブジェクトであるプロキシです。データ コンテキストには、ぞれぞれがデータベース内のテーブルを表すテーブル オブジェクトが含まれます。各 Table オブジェクトは、データベース内のデータ行に対応するエンティティで構成されます。各エンティティは、属性を備えた POCO (Plain Old CLR Object) です。各エンティティの属性により、データベース テーブルの構造が決まり、データのオブジェクト モデルとデータベースのスキーマとの間のマッピングが定義されます。たとえば、Name プロパティと PhoneNumber プロパティを有するエンティティは、Name 列と PhoneNumber 列を持つデータベース テーブルになります。

LINQ to SQL では、オブジェクトリレーショナル マッピング機能が利用できます。この機能を使用すると、マネージ アプリケーションで統合言語クエリ (LINQ) を使用してリレーショナル データベースと通信することができます (Transact-SQL のみを使用)。LINQ to SQL は、.NET Framework マネージ コードで表現したオブジェクト モデルを、リレーショナル データベースにマッピングします。アプリケーションを実行すると、LINQ to SQL は統合言語クエリを Transact-SQL に変換してから、それらのクエリをデータベースに送信して実行します。データベースから結果が返されると、LINQ to SQL は返された結果をそれぞれのプログラミング言語で操作できるオブジェクトに変換します。詳細については、「LINQ to SQL」を参照してください。

注注:

Windows Phone の LINQ to SQL は、データ定義言語 (DDL) ステートメントやデータ モデリング言語 (DML) ステートメントを含めて、Transact-SQL の実行を直接サポートしていません。また、Windows Phone アプリケーションでは、LINQ to SQL を使用して ADO.NET オブジェクトに直接アクセスすることはできません。詳細については、「Windows Phone での LINQ to SQL のサポート」を参照してください。

SQL Server のリレーショナル データベースを使用するデスクトップ アプリケーションと同様に、Windows Phone アプリケーションは、LINQ to SQL を使用することにより、ローカル データベースを使用して、データの選択、挿入、更新、および削除を行うことができます。これにより、Windows Phone アプリケーションでは、LINQ の強力なクエリ機能とストレージ効率に優れたリレーショナル データベースを利用することができます。電話に搭載されたリソースは PC よりも少ないため、ローカル データベースは一般的なデータベースといくつかの点で異なっています。ローカル データベースには、次のような違いがあります。

  • ローカル データベースは、Windows Phone アプリケーションのプロセスで実行されます。Microsoft SQL Server などのクライアントサーバー型データベースと異なり、バックグラウンド サービスとして連続して実行されることはありません。

  • ローカル データベースは、対応する Windows Phone アプリケーションからのみアクセスできます。データベース ファイルは分離ストレージに存在するため、他のアプリケーションからこのデータにアクセスすることはできません。

  • ローカル データベースは LINQ to SQL でのみアクセスできます。Transact-SQL はサポートされていません。

標準のアプリケーションの展開では、アプリケーションの初回実行時に、分離ストレージ内にローカル データベースが作成されます。その後、アプリケーションが使用されるたびに、アプリケーション データがデータベースに追加されます。アプリケーションと一緒に事前設定された一連の参照データを含めるには、アプリケーションにローカル データベース ファイルを追加します。手順については、「方法: Windows Phone アプリケーションと共に参照データベースを展開する」を参照してください。

アプリケーションと一緒に参照データを展開するには、以下の手順を実行する必要があります。

  1. ヘルパー アプリケーションを作成する: ヘルパー アプリケーションは開発用コンピューターで実行し、分離ストレージにローカル データベースを作成して、目的の参照データを格納するデータベースを読み込みます。

  2. ヘルパー アプリケーションからローカル データベースを抽出する: 分離ストレージ エクスプローラー (ISETool.exe) を使用して、ヘルパー アプリケーションからコンピューター上のフォルダーにデータベースをコピーします。Isolated Storage Explorer の詳細については、「方法: 分離ストレージ エクスプローラー ツールを使用する」を参照してください。

  3. プライマリ アプリケーションを作成する: 参照データを使用するアプリケーションを作成します。

  4. プライマリ アプリケーションに参照データを追加する: Visual Studio を使用して、ローカル データベース ファイルをコンピューター上の保存したフォルダーから、プライマリ アプリケーションに追加します。アプリケーション アセンブリのサイズを最小にするには、ファイルをコンテンツとして保存します。

ローカル データベースがアプリケーションと一緒に展開されると、読み取り専用状態でインストール フォルダー内に置かれます。インストール フォルダーは分離ストレージと異なります。この場所のデータベース ファイルを処理するには、appdata: プレフィックスを使用します。データベース接続文字列でこのプレフィックスを使用する例については、「Windows Phone のローカル データベース接続文字列」を参照してください。

参照データを格納するデータベースを変更するには、それをインストール フォルダーから移動して、分離ストレージに保存してから、データベースを変更します。データベース ファイルを移動するには、Application.GetResourceStream メソッドでインストール フォルダーからストリームを作成し、IsolatedStorageFileStream.Write メソッドで分離ストレージにストリームを書き込むことによって、ストリームベースのコピーを実行できます。次の例に、ストリーム オブジェクトを作成する場合にインストール フォルダー内のデータベース ファイルを処理する方法を示します。

Stream str = Application.GetResourceStream(new Uri("appdata:/MyReferenceDB.sdf", UriKind.Relative)).Stream;

ローカル データベースを作成するには、最初にデータ コンテキストとエンティティを定義する必要があります。これらのクラスでは、データのオブジェクト モデルとデータベースのスキーマとの間のマッピングを定義します。LINQ to SQL のオブジェクトリレーショナル機能は、対応するデータ コンテキストにマッピングされるリレーショナル データベースを作成するのに、これらのマッピングの詳細定義に依存します。

エンティティごとに、LINQ to SQL のマッピング属性を使用してマッピングの詳細が指定されます。これらの属性では、テーブル、列、主キー、およびインデックスなどのデータベースごとの機能が指定されます。詳細については、「属性ベースの対応付け (LINQ to SQL)」を参照してください。たとえば、次のコードは、ToDoDataContext という名前のデータ コンテキストと、ToDoItem という名前のエンティティ クラスの最初の部分を示しています。

public class ToDoDataContext : DataContext
{
    // Specify the connection string as a static, used in main page and app.xaml.
    public static string DBConnectionString = "Data Source=isostore:/ToDo.sdf";

    // Pass the connection string to the base class.
    public ToDoDataContext(string connectionString): base(connectionString) { }

    // Specify a single table for the to-do items.
    public Table<ToDoItem> ToDoItems;
}

// Define the to-do items database table.
[Table]
public class ToDoItem : INotifyPropertyChanged, INotifyPropertyChanging
{
    // Define ID: private field, public property, and database column.
    private int _toDoItemId;

    [Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
    public int ToDoItemId
    {
        get
        {
            return _toDoItemId;
        }
        set
        {
            if (_toDoItemId != value)
            {
                NotifyPropertyChanging("ToDoItemId");
                _toDoItemId = value;
                NotifyPropertyChanged("ToDoItemId");
            }
        }
    }
         . . .
         . . .
         . . .

注注:

これは、データ コンテキスト コードの一部です。ローカル データベースを使用するアプリケーションを作成する手順については、「方法: Windows Phone 用の基本的なローカル データベース アプリケーションを作成する」を参照してください。

各自のコードでローカル データベース機能を使用する場合は、コード ファイルの先頭に次のディレクティブが必要になります。


using System.Data.Linq;
using System.Data.Linq.Mapping;
using Microsoft.Phone.Data.Linq;
using Microsoft.Phone.Data.Linq.Mapping;

LINQ to SQL の一般的なマッピング属性の一部を次の表に示します。詳細なリストについては、System.Data.Linq.Mapping Namespace を参照してください。

属性

使用例

説明

TableAttribute

[Table]

データベース テーブルに関連付けられたエンティティ クラスとしてクラスを指定します。

ColumnAttribute

[Column(IsPrimaryKey = true)]

データベース テーブルの列にクラスを関連付けます。IsPrimaryKey では、主キーを指定します。このため、既定でインデックスが作成されます。

IndexAttribute

[Index(Columns="Column1,Column2 DESC", IsUnique=true, Name="MultiColumnIndex")]

テーブル レベルで記述されます。テーブルの追加インデックスを指定します。各インデックスは 1 つまたは複数の列をカバーすることができます。

AssociationAttribute

[Association(Storage="ThisEntityRefName", ThisKey="ThisEntityID", OtherKey="TargetEntityID")]

外部キーと主キーの関連付けなどの、関連付けを表すプロパティを指定します。

DataContext オブジェクトを作成した後に、ローカル データベースを作成し、各種データベース操作を実行することができます。ToDoDataContext クラスのデータ コンテキストに基づいて、データベースを作成するコード例を次に示します。

// Create the database if it does not yet exist.
using (ToDoDataContext db = new ToDoDataContext("isostore:/ToDo.sdf"))
{
    if (db.DatabaseExists() == false)
    {
        // Create the database.
        db.CreateDatabase();
    }
}

この例に示すように、データ コンテキストを作成するには、最初にデータ コンテキストとデータベース ファイルのファイルの場所を指定する必要があります。DataContext のコンストラクターの値は、データベース ファイル名が ToDo.sdf であることを指定しています。この値の isostore:/ 部分は、ファイルが分離ストレージに配置されていることを示しています。次に、CreateDatabase メソッドを使用し、DatabaseExists メソッドでデータベースがまだ存在していないことを確認してからデータベースを作成します。

注注:

データベースが作成されると、自動的にバージョン 0 が割り当てられます。データベースのバージョンを特定するには、DatabaseSchemaUpdater クラスを使用します (このトピックであとから説明する、「データベース スキーマの変更」を参照してください)。

ローカル データベースの作成が完了したら、LINQ とデータ コンテキストを使用して、ローカル データベースを使用することができます。以下のサブセクションでは、データベースのデータを選択、挿入、更新、および削除する方法について説明します。これらの操作を実行するアプリケーションを作成する手順については、「方法: Windows Phone 用の基本的なローカル データベース アプリケーションを作成する」を参照してください。

データの選択 (データベース クエリ)

Windows Phone では、データベースのクエリに統合言語クエリ (LINQ) を使用します。LINQ はオブジェクトの世界とデータの世界の橋渡しをします。LINQ to SQL のクエリでは、LINQ のクエリと同じ構文を使用します。LINQ クエリの詳細については、「LINQ クエリの概要 (C#)」を参照してください。

LINQ to SQL のクエリで参照されるオブジェクトはデータベース内のレコードにマッピングされます。そのため、LINQ to SQL はクエリの実行方法が他 LINQ テクノロジと異なります。一般的な LINQ クエリはアプリケーション層においてメモリ内で実行されます。LINQ to SQL では、ランタイムのオブジェクトリレーショナル機能を使用して、各 LINQ クエリが Transact-SQL に変換されてから、データベース内で直接実行されます。これにより、大規模なデータベースから数レコードを選択するようなクエリで、パフォーマンスの向上を実現することができます。

次の例では、toDoDB という名前の DataContext オブジェクトが LINQ to SQL で照会され、結果が ToDoItems という名前の ToDoItem オブジェクトの ObservableCollection に配置されます。遅延実行により、ToDoItems コレクションがインスタンス化されるまでデータベース クエリは実際には実行されません。

// Define query to gather all of the to-do items.
var toDoItemsInDB = from ToDoItem todo in toDoDB.ToDoItems
                    select todo;

// Execute query and place results into a collection.
ToDoItems = new ObservableCollection<ToDoItem>(toDoItemsInDB);

データの挿入

データベースへのデータの挿入は 2 段階の処理で実行されます。最初にデータ コンテキストにオブジェクトを追加してから、データ コンテキストの SubmitChanges メソッドを呼び出して、データベース内の行としてデータを保持します。詳細については、「方法: 行をデータベースに挿入する (LINQ to SQL)」を参照してください。

次の例では、ToDoItem オブジェクトが作成され、toDoDB という名前のデータ コンテキストの ToDoItems オブザーバブル コレクションと対応するデータベース テーブルに追加されます。

// Create a new to-do item based on text box.
ToDoItem newToDo = new ToDoItem { ItemName = newToDoTextBox.Text };

// Add the to-do item to the observable collection.
ToDoItems.Add(newToDo);
            
// Add the to-do item to the local database.
toDoDB.ToDoItems.InsertOnSubmit(newToDo); 

重要な注重要な注:

データは SubmitChanges メソッドが呼び出されるまでデータベースに保存されません。

データの更新

ローカル データベースのデータの更新は、3 段階で行われます。最初に、データベースで更新対象のオブジェクトをクエリします。続いて、必要に応じてオブジェクトを変更します。最後に、SubmitChanges メソッドを呼び出してローカル データベースの変更を保存します。詳細については、「方法: データベースの行を更新する (LINQ to SQL)」を参照してください。

データ コンテキストのオブジェクトをページ上のコントロールにバインドすると、ユーザーの操作に基づいてデータ コンテキストを自動的に更新することができます。この場合は、必要なときに SubmitChanges メソッドを呼び出すだけで済みます。この手法の例は、ローカル データベースのサンプル アプリケーションにあります。「方法: Windows Phone 用の基本的なローカル データベース アプリケーションを作成する」を参照してください。次に、ユーザーがページから移動したときに、SubmitChanges メソッドを呼び出すコード例を示します。

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{ 
    //Call base method
    base.OnNavigatedFrom(e);
            
    //Save changes to the database
    toDoDB.SubmitChanges();
}
重要な注重要な注:

データは SubmitChanges メソッドが呼び出されるまでデータベース内で更新されません。

データの削除

データベース内のデータの削除も、3 つの手順で構成されます。最初に、データベースで削除対象のオブジェクトをクエリします。次に、削除するオブジェクトが 1 つ以上あるかどうかに応じて、DeleteOnSubmit または DeleteAllOnSubmit メソッドを呼び出して、該当するオブジェクトを削除保留状態にします。最後に、SubmitChanges メソッドを呼び出してローカル データベースの変更を保存します。詳細については、「方法: 行をデータベースから削除する (LINQ to SQL)」を参照してください。

次の例では、ToDoItem オブジェクトが toDoDB という名前のデータベースから削除されます。オブジェクトが 1 つだけ削除されるため、SubmitChanges の前に DeleteOnSubmit メソッドが呼び出されます。

//Get a handle for the to-do item bound to the button
ToDoItem toDoForDelete = button.DataContext as ToDoItem;

//Remove the to-do item from the observable collection
ToDoItems.Remove(toDoForDelete);

//Remove the to-do item from the local database
toDoDB.ToDoItems.DeleteOnSubmit(toDoForDelete);

//Save changes to the database
toDoDB.SubmitChanges();

重要な注重要な注:

データは SubmitChanges メソッドが呼び出されるまでデータベースから削除されません。

Windows Phone アプリケーションの変更では、ローカル データベース スキーマへの変更が必要になる場合があります。ローカル データベース スキーマの変更では、最初に対応するデータ コンテキストのオブジェクト モデルを変更します。Microsoft.Phone.Data.Linq 名前空間には、データベース スキーマの変更に役立つ DatabaseSchemaUpdater クラスが用意されています。このクラスの使用例については、「チュートリアル: Windows Phone のローカル データベース アプリケーションを更新する」を参照してください。

DatabaseSchemaUpdater クラスでは、テーブル、列、インデックス、または関連付けの追加など、データベースに対する追加的な変更を実行できます。より複雑な変更を行う場合は、必要に応じて、データベースを新規に作成し、新しいスキーマにデータをコピーする必要があります。DatabaseSchemaUpdater クラスでは DatabaseSchemaVersion プロパティが利用できます。このプロパティを使用すると、データベースの各種バージョンをプログラムで区別することができます。

重要な注重要な注:

Execute メソッドが呼び出されるまでは DatabaseSchemaUpdater オブジェクトからの更新を反映するため、データベースは変更されません。このメソッドが呼び出されると、バージョンの更新を含むすべての変更内容がローカル データベースに 1 回のトランザクションとして送信されます。1 回のトランザクションを使用することで、ユーザーがアップグレード中にアプリケーションを終了した場合などでも、データベースの完全性を維持することができます。

次に、DatabaseSchemaUpdater クラスを使用し、DatabaseSchemaVersion プロパティに基づいてデータベースを変更する例を示します。

using (ToDoDataContext db = new ToDoDataContext(("isostore:/ToDo.sdf")))
{
        //Create the database schema updater
        DatabaseSchemaUpdater dbUpdate = db.CreateDatabaseSchemaUpdater();

        //Get database version
        int dbVersion = dbUpdate.DatabaseSchemaVersion;

        //Update database as applicable
        if (dbVersion < 5)
        {   //Copy data from existing database to new database 
            MigrateDatabaseToLatestVersion();
        }
        else if (dbVersion == 5)
        {   //Add column to existing database to match the data context
            dbUpdate.AddColumn<ToDoItem>("TaskURL");
            dbUpdate.DatabaseSchemaVersion = 6;
            dbUpdate.Execute();
        }
}

注注:

分離ストレージに保存されたファイル (ローカル データベース ファイルを含む) は、アプリケーションの更新中には変更されません。

ローカル データベースでは、パスワード保護と暗号化を利用してデータベースを保護することができます。データベースでパスワードを使用すると、データベース全体が暗号化されます。データベースを暗号化するには、データベースを作成する前にデータベース接続文字列 (データ コンテキスト コンストラクター) でパスワードを提供します。パスワードはデータベースにアクセスするたびに入力する必要があります。作成済みのデータベースを暗号化することはできません。データベースは AES-128 を使用して暗号化され、パスワードは SHA-256 を使用してハッシュされます。

次に、データベース接続文字列でパスワードを指定して、暗号化されたデータベースを作成する例を示します。

// Create the data context, specify the database file location and password
ToDoDataContext db = new ToDoDataContext ("Data Source=’isostore:/ToDo.sdf’;Password=’securepassword’");

// Create an encrypted database after confirming that it does not exist
if (!db.DatabaseExists()) db.CreateDatabase();

ヒントヒント:

インデックス付きでない列の一部のみを暗号化する必要がある場合は、データベース全体を暗号化せずに、データベースに追加する前に該当データを暗号化することで、パフォーマンスの向上させることができます。データ暗号化の詳細については、「方法: Windows Phone アプリケーションでデータを暗号化する」を参照してください。

ローカル データベースでの接続文字列の使用について詳しくは、「Windows Phone のローカル データベース接続文字列」を参照してください。

表示: