
[WPF|CSharp]Entity framework 5.0+SQL Server Compact 4.1でマイグレーション サンプル#TrySSCE4

EntityFramework5.0とSQL Server Compact4.0をインストールしていない環境へアプリケーションをインストールしても動くようにする。
データベースはマイグレーションできるようにして、テーブルの項目やらが変更された場合に検知して勝手に初期化がかかるようにする。
実行ファイルと同じ場所に以下の構成でライブラリを用意する
EntityFramework.dll
※↑はNuGet使ってプロジェクトに組み込む
System.Data.SqlServerCe.dll
System.Data.SqlServerCe.Entity.dll
amd64/sqlceca40.dll
amd64/sqlcecompact40.dll
amd64/sqlceer40EN.dll
amd64/sqlceer40JA.dll
amd64/sqlceme40.dll
amd64/sqlceqp40.dll
amd64/sqlcese40.dll
x86/sqlceca40.dll
x86/sqlcecompact40.dll
x86/sqlceer40EN.dll
x86/sqlceer40JA.dll
x86/sqlceme40.dll
x86/sqlceqp40.dll
x86/sqlcese40.dll
ja/EntityFramework.resources.dll
ja/System.Data.SqlServerCe.Entity.resources.dll
ja/System.Data.SqlServerCe.resources.dll
これらは
C:\Program Files (x86)\Microsoft SQL Server Compact Edition\v4.0
このあたりに入ってる。
app.configに接続情報を書き込まないとマイグレーションするときに落ちるので注意!
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </configSections> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" /> </startup> <system.data> <DbProviderFactories> <!-- プライベートな(実行ファイルと一緒にSqlServerCe.dllを配布するときに必要) --> <remove invariant="System.Data.SqlServerCe.4.0"></remove> <!-- これ書かないとSQL Server Compactではなく、SQL Server Expressに書き込みに行く --> <add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91" /> </DbProviderFactories> </system.data> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <!-- ↓ これで読み込みパス決めれる? <probing privatePath="SqlCe4"/> --> <dependentAssembly> <assemblyIdentity name="System.Data.SqlServerCe" publicKeyToken="89845dcd8080cc91" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.1" /> </dependentAssembly> </assemblyBinding> </runtime> <entityFramework> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework"> <parameters> <parameter value="System.Data.SqlServerCe.4.0" /> </parameters> </defaultConnectionFactory> </entityFramework> <!-- ここで接続情報を指定をしないとマイグレーションの時にエラーが出る --> <connectionStrings> <add name="TryDBContext" connectionString="Data Source=try.sdf" providerName="System.Data.SqlServerCe.4.0" /> </connectionStrings> </configuration>
●
これは実際データベースに書き込まれるモノ。
コメントアウトされているところを追加したりするとデータベースにも即反映されるようになる。
[Required]とかはデータベース内の要素を設定してる。
コードファーストなデータベースの作り方をするので直接テーブル編集をすることはない。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace TrySSCE4 { public class ReplyMessage { [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] [Display(Name = "メッセージID")] public Int64 Id { get; set; } [Required, MaxLength(200)] [Display(Name = "メッセージ")] public string Message { get; private set; } [Required, MaxLength(200)] [Display(Name = "メッセージ2")] public string Message2 { get; private set; } [Required, MaxLength(200)] [Display(Name = "メッセージ3")] public string Message3 { get; private set; } [Required, MaxLength(200)] [Display(Name = "メッセージ4")] public string Message4 { get; private set; } /* [Required] [Display(Name = "メッセージ5")] public string Message5 { get; private set; } [Required] [Display(Name = "メッセージ6")] public string Message6 { get; private set; } [Required] [Display(Name = "メッセージ7")] public string Message7 { get; private set; } [Required] [Display(Name = "メッセージ9")] public string Message8 { get; private set; } */ /// <summary> /// デフォルトコンストラクタ /// </summary> public ReplyMessage() { // このコンストラクタ無いとエラー吐いて落ちるよ } public ReplyMessage(string message) { if (message == null) { throw new ArgumentNullException("message"); } this.Message = message; this.Message2 = "<" + message + ">"; this.Message3 = "*" + message + "*"; this.Message4 = this.Message + " " + this.Message2; /* this.Message5 = "今日の天気は"; this.Message6 = "晴れかな?"; this.Message7 = "曇りかな?"; this.Message8 = "どうかな?"; */ } public override string ToString() { return "Id:" + this.Id.ToString() + "\tMessage:" + this.Message + "\tMessage2" + this.Message2 + "\tMessage3" + this.Message3 + "\tMessage4" + this.Message4;/* + "\tMessage5" + this.Message5 + "\tMessage6" + this.Message6 + "\tMessage7" + this.Message7 + "\tMessage9" + this.Message9;*/ } } }
●
メインウィンドウの処理。
ボタンをクリックすると新しいデータをデータベースに書き込んで、それをそのまま表示する。
using System; using System.Collections.Generic; using System.Linq; using System.Windows; using Microsoft.Windows.Controls.Ribbon; using System.Data.Entity; using System.Diagnostics; using System.IO; namespace TrySSCE4 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : RibbonWindow { public MainWindow() { InitializeComponent(); try { // DB無い時は作る if (File.Exists("try.sdf") == false) { // イニシャライザ Database.SetInitializer(new DropCreateDatabaseIfModelChanges<TryDbContext>()); // データーベースのマイグレート設定 } else { // var maigrate = new MigrateDatabaseToLatestVersion<TryDbContext, Configulation>(); Database.SetInitializer(maigrate); } } catch (Exception exp) { this.ShowExpMsg(exp); } } // ボタンがクリックされたときに呼ばれる private void button5_Click(object sender, RoutedEventArgs e) { string res = ""; try { using (var context = new TryDbContext()) { context.ReplyMessages.Add(new ReplyMessage("ためしの書き込み")); context.SaveChanges(); foreach (var elem in context.ReplyMessages) { res += elem.ToString() + "\n"; Debug.Print(elem.ToString()); } } MessageBox.Show(res); } catch (Exception exp) { this.ShowExpMsg(exp); /* MessageBox.Show(exp.Message); if (exp.InnerException != null) { MessageBox.Show(exp.InnerException.Message); } * */ } } // 例外メッセージをInnerExceptionがあるだけ表示する // 例外はネストしていくので、一番表面のやつだけ表示しても意味がわからないことが多い private void ShowExpMsg(Exception exp) { string msg = ""; Exception curr = exp; int count = 0; while (curr != null) { msg += count + ". " + curr.Message + "\n"; curr = curr.InnerException; count++; } Debug.Print(msg); MessageBox.Show(msg); } } }
●
マイグレーション処理をするところ。
AutomaticMigrationsEnabledにtrueを設定するとテーブルの要素が増えたときに適当に初期化してくれる。
using System; using System.Collections.Generic; using System.Linq; using System.Data.Entity.Migrations; namespace TrySSCE4 { /// <summary> /// イニシャライザ(DBの初期化やら、マイグレーションやら) /// </summary> public class Configulation : DbMigrationsConfiguration<TryDbContext> { /// <summary> /// Initializes a new instance of the TryDbContextInitializer class. /// </summary> public Configulation() { // マイグレーションを自動でするように // これしてReplyMessageに何か追加してエラーでたらapp.configに // connectionStringがきっちり書かれてるか見直す this.AutomaticMigrationsEnabled = true; this.AutomaticMigrationDataLossAllowed = true; } /// <summary> /// マイグレーションが終わった後に呼び出される。たぶん初期化しれってことじゃね? /// </summary> /// <param name="context"></param> protected override void Seed(TryDbContext context) { base.Seed(context); } } }
[Android]電話帳にアクセスして表示するサンプル#tryPhoneBook00 [Android]ViewPagerを使って画面をスワイプ、フリックするサンプル#tryVie...