(Windows Phone Advent Calendar 2011 の 18 日目です。)
Windows Phone 7.5 アプリケーションでは、ローカル データベースとして SQL Server Compact を利用できます。
データベース ファイルの拡張子は .sdf です。
アプリケーションから接続するには LINQ to SQL を利用します。
今回は、Database First で既存のデータベース ファイル (.sdf) からコードを自動生成し、
Windows Phone 7.5 アプリケーションで動作させるまでの一連の手順について紹介します。
ちなみに、MSDN ライブラリの Windows Phone のローカル データベースの概要を見ると、
Code First な方法は載っているのですが Database First な方法は載っていません。
なお、Code First な方法についての日本語の解説は、
はぢめてのWindows Phone 7でのデータベース(Linq to Sql) などを参照するとよいでしょう。
■ データベース ファイルを準備する
「既存のデータベース ファイル (.sdf)」と書きましたが、
これまでに Windows Phone プラットフォーム以外で使用されていたものや、新規に作成したものも含みます。
ただし、方法: Windows Phone アプリケーションと共に参照データベースを展開するの
「重要な注」に記述されている通り、デスクトップで作成された SQL Server Compact データベースを
Windows Phone アプリケーションで動作させることは公式にサポートされていません。
したがって、自己責任で利用しましょう。
以下に、SQL Server Compact のデータベース ファイルを新規に作成する方法を簡単に示します。
(1) SQL Server Management Studio を使う場合
[サーバーへの接続] ダイアログの [サーバーの種類] で SQL Server Compact を選択し、
[データベース ファイル] で <新しいデータベース…> を選択します。
すると別のダイアログが表示されるので、ファイル名を指定します。
あとはこのデータベース ファイルに接続してテーブルを定義します。
ただし、SQL Server の場合とは異なり、データベース ダイアグラムは利用できません。
(2) Visual Studio を使う場合
Windows Phone 系のプロジェクトからでは作成できません。
Windows アプリケーション系のプロジェクトから次の図のように作成します。
あとはサーバー エクスプローラーからデータベース ファイルに接続してテーブルを定義します。
コンテキスト メニューの [テーブル データの表示] からデータをグリッド形式で操作することもできます。
SQL を利用することもできます。
さて、初期データを外部から一括で取り込みたい場合についてですが、
SQL Server Compact データベースには bcp ユーティリティでデータを一括でインポートできません。
次のような方法が考えられます。
- Integration Services を利用する (未検証)
- 後述する Proxy コードを生成してからコンソール アプリケーションを作成してデータを投入する
- INSERT 文を生成して Management Studio や Visual Studio で実行する
■ データベース ファイルからコードを生成する
SQL Server などのデータベースを対象とした開発では、
Visual Studio で既存のデータベースから Proxy クラスを自動生成するという方法がよく用いられています。
しかし残念ながら、Visual Studio には .sdf ファイルから LINQ to SQL 用のコードを自動生成する機能がありません。
そこで、SqlMetal.exe というコマンドライン ツールを利用します。
これを使うと、.sdf ファイルから LINQ to SQL 用のコードを自動生成できます。
SqlMetal.exe は Windows SDK に含まれています (Visual Studio とともにインストールされます)。
例えば、次に示すようなバッチ ファイルを作成します。
SqlMetal.exe の引数には、.sdf ファイルのパス、作成されるコード ファイルのパス、
型指定された DataContext の名前空間とクラス名を指定します。絶対パスおよび相対パスが使えます。
CreateDataContext.bat
rem 64 bit OS の場合
set SqlMetal="C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\SqlMetal.exe"
%SqlMetal% Test.sdf /code:TestDataContext.cs /namespace:PhoneApp1 /context:TestDataContext /pluralize
このバッチ ファイルを実行すると TestDataContext.cs が生成されます。
ただし、本来これは .NET Framework 用のコードであり、Windows Phone 用のプロジェクトでは
型指定された DataContext クラスの一部のコンストラクターがコンパイル エラーとなるので、それらを手動で削除します。
TestDataContext.cs
// ・・・ (省略) ・・・
public partial class TestDataContext : System.Data.Linq.DataContext
{
// ・・・ (省略) ・・・
public TestDataContext(string connection) :
base(connection, mappingSource)
{
OnCreated();
}
/* IDbConnection は存在しません。
public TestDataContext(System.Data.IDbConnection connection) :
base(connection, mappingSource)
{
OnCreated();
}
*/
public TestDataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection, mappingSource)
{
OnCreated();
}
/* IDbConnection は存在しません。
public TestDataContext(System.Data.IDbConnection connection, System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection, mappingSource)
{
OnCreated();
}
*/
public System.Data.Linq.Table<Company> Companies
{
get
{
return this.GetTable<Company>();
}
}
public System.Data.Linq.Table<Line> Lines
{
get
{
return this.GetTable<Line>();
}
}
// ・・・ (省略) ・・・
その他の注意点
(1) Visual Studio コマンド プロンプトを利用すれば、SqlMetal.exe の絶対パスは必要ありません。
(2) このコードは、同じテーブル構造を持った SQL Server などに接続する場合にも利用できます。
コンストラクターの引数に渡す接続文字列を変えるだけです。
(3) 引数に /pluralize を付加すると、単語の単数形・複数形を適切に判断してコードを生成します。
上記の例では、Companies テーブルのエンティティの名前が Company になっています。
■ データベース ファイルを配置する
上記で準備したデータベース ファイル (.sdf) とコード ファイル (.cs) を Windows Phone アプリケーションの
プロジェクトに追加します (自動的にデータベース ファイルの [ビルド アクション] がコンテンツ、
コード ファイルの [ビルド アクション] がコンパイルになるはずです)。
また、プロジェクトの参照設定に System.Data.Linq を追加します。
初回実行時にこのデータベース ファイルを分離ストレージに配置するために、
アプリケーションの Launching イベントの処理を次のように追加します。
なお、接続文字列が特殊なので注意が必要です。isostore:/ のあとに分離ストレージ内でのパスを指定します。
App.xaml.cs
// ・・・ (省略) ・・・
private static readonly Uri TestContentUri = new Uri("Test.sdf", UriKind.Relative);
private const string TestStoragePath = "Test.sdf";
private const string TestConnectionString = "Data Source=isostore:/Test.sdf";
// (たとえば、[スタート] メニューから) アプリケーションが起動するときに実行されるコード
// このコードは、アプリケーションが再アクティブ化済みの場合には実行されません
private void Application_Launching(object sender, LaunchingEventArgs e)
{
using (var context = new TestDataContext(TestConnectionString))
{
if (!context.DatabaseExists())
{
using (var input = Application.GetResourceStream(TestContentUri).Stream)
using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
using (var output = storage.CreateFile(TestStoragePath))
{
input.CopyTo(output);
}
}
}
}
// ・・・ (省略) ・・・
■ データベース ファイルに接続する
ここまでできれば、もう難しいことはありません。
データベースに接続してデータを操作するには LINQ to SQL を利用します。
private const string TestConnectionString = "Data Source=isostore:/Test.sdf";
public static Company[] GetCompanies()
{
using (var context = new TestDataContext(TestConnectionString))
{
return context.Companies.ToArray();
}
}
バージョン情報
Windows Phone OS 7.1
Visual Studio 2010 SP1
参照
Windows Phone のローカル データベースの概要 (MSDN)
方法: Windows Phone アプリケーションと共に参照データベースを展開する (MSDN)
SqlMetal.exe (コード生成ツール) (MSDN)
Using SqlMetal to generate Windows Phone Mango Local Database classes (WindowsPhoneGeek)
はぢめてのWindows Phone 7でのデータベース(Linq to Sql) (neue cc)
Local Database for Windows Phone (雑記 – otherwise)