Xamarin.iOS で EntityFrameworkCore を使うことができたのでメモしておく。 データベースは SQLite。 なのでパッケージは Microsoft.EntityFrameworkCore.Sqlite をインストールすることになる。
Visual Studio で NuGet パッケージをインストールしたら、 EntityFrameworkCore + SQLite を使うようにコードで構成する。 ASP.NET Core のときみたいに DI は使わない。
using Foundation; using Microsoft.EntityFrameworkCore; using System; using System.IO; using System.Linq; using System.Threading.Tasks; using UIKit; namespace HelloXamarin { public class Application { static void Main(string[] args) { UIApplication.Main(args, null, "AppDelegate"); } } [Register("AppDelegate")] public class AppDelegate : UIApplicationDelegate { public override UIWindow Window { get; set; } public ApplicationDbContext DbContext { get; private set; } public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) { // SQLite を初期化 SQLitePCL.Batteries_V2.Init(); // データベースがなければ作る DbContext = new ApplicationDbContext(); DbContext.Database.EnsureCreated(); Window = new UIWindow(UIScreen.MainScreen.Bounds); Window.RootViewController = new UINavigationController( new MainViewController(DbContext)); Window.MakeKeyAndVisible(); return true; } public override void WillTerminate(UIApplication application) { DbContext?.Dispose(); } } public class MainViewController : UITableViewController { readonly ApplicationDbContext _dbContext; Stamp[] _stamps = new Stamp[0]; UIBarButtonItem _addButton; public MainViewController(ApplicationDbContext dbContext) : base(UITableViewStyle.Plain) { Title = "Hello Xamarin"; _dbContext = dbContext; _addButton = new UIBarButtonItem( UIBarButtonSystemItem.Add, HandleAddButtonClick); } async void HandleAddButtonClick(object sender, EventArgs e) { await AddStampAsync(); await LoadStampsAsync(); TableView.InsertRows( new[] { NSIndexPath.FromItemSection(0, 0) }, UITableViewRowAnimation.Fade); } public override async void ViewDidLoad() { base.ViewDidLoad(); NavigationItem.RightBarButtonItem = _addButton; await LoadStampsAsync(); } public override nint RowsInSection(UITableView tableView, nint section) { return _stamps.Length; } public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath) { var cell = new UITableViewCell(UITableViewCellStyle.Default, "StampCell"); var stamp = _stamps[indexPath.Row]; cell.TextLabel.Text = stamp.StampedAt.ToString(); return cell; } async Task AddStampAsync() { _dbContext.Stamps.Add(new Stamp()); await _dbContext.SaveChangesAsync(); } async Task LoadStampsAsync() { _stamps = await _dbContext.Stamps .OrderByDescending(s => s.StampedAt) .ToArrayAsync(); } } public class Stamp { public string Id { get; set; } = Guid.NewGuid().ToString(); public DateTime StampedAt { get; set; } = DateTime.UtcNow; } public class ApplicationDbContext : DbContext { public ApplicationDbContext() : base() { Stamps = Set<Stamp>(); } public DbSet<Stamp> Stamps { get; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { var dbPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "..", "Library", "helloxamarin.db"); // SQLite を使う optionsBuilder.UseSqlite( connectionString: $"Filename={dbPath}"); base.OnConfiguring(optionsBuilder); } } }
SQLitePCL.Batteries_V2.Init()
で SQLite の初期化は必須。
あと、UseSqlite
で名前付き引数 connectionString
を明示的に指定しているのは、
これをしないと DbConnection
を引数で受け取るオーバーロードが影響してビルドエラーになってしまったから。
少々ハマりもしたけど、思ったよりはすんなり使えた感じ。 Xamarin でデータベースが必要になったとき、 今までは SQLite-net PCL や Realm を選んでいたけど、 ASP.NET Core で慣れている EntityFrameworkCore も自分的にはアリだな。