過去記事
DBの変更
JavaScriptがバックエンドのときはいい感じにDBの変更をしてくれる(それはそれで怖いっちゃ怖いけど)んですが、.NETバックエンドだとそういう感じにはなっていません。 というか、どうやるのか書いてません。書いてませんがEntityFramework 6.0を使ってるのでおそらくマイグレーションするのでしょう。
Entity Framework Code First Migrations
とりあえず、今回はローカルDBは考えてなかったのでWeb.configの接続文字列にクラウドの接続文字列を追加しましょう(これは悪手なので後で正しいやり方をフォローする記事を書く(予定))
そして、パッケージマネージャーコンソールを開いて、既定のプロジェクトをMobile Appsのサーバープロジェクトに変更して以下のコマンドを打ち込みます。
PM> Enable-Migrations
試しに、UserIdを追加したいので、TodoItem
にUserId
列を追加します。
using Microsoft.Azure.Mobile.Server; namespace SampleMobileApp.DataObjects { public class TodoItem : EntityData { public string Text { get; set; } public bool Complete { get; set; } public string UserId { get; set; } } }
そして、TodoControllerにUserIdでのフィルタリング等を追加します。 ただ、このロジックはIDを知ってる人なら、その情報にはアクセスできるという前提で動いています。(それ以上堅牢なロジックの組み方がわからなかったので、これが限界なのかも)
using System.Linq; using System.Threading.Tasks; using System.Web.Http; using System.Web.Http.Controllers; using System.Web.Http.OData; using Microsoft.Azure.Mobile.Server; using SampleMobileApp.DataObjects; using SampleMobileApp.Models; using System.Security.Claims; namespace SampleMobileApp.Controllers { [Authorize] public class TodoItemController : TableController<TodoItem> { protected override void Initialize(HttpControllerContext controllerContext) { base.Initialize(controllerContext); MobileServiceContext context = new MobileServiceContext(); DomainManager = new EntityDomainManager<TodoItem>(context, Request); } // GET tables/TodoItem public IQueryable<TodoItem> GetAllTodoItems() { var sid = (this.User as ClaimsPrincipal)?.FindFirst(ClaimTypes.NameIdentifier)?.Value; return Query().Where(x => x.UserId == sid); } // GET tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959 public SingleResult<TodoItem> GetTodoItem(string id) { return Lookup(id); } // PATCH tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959 public Task<TodoItem> PatchTodoItem(string id, Delta<TodoItem> patch) { return UpdateAsync(id, patch); } // POST tables/TodoItem public async Task<IHttpActionResult> PostTodoItem(TodoItem item) { item.UserId = (this.User as ClaimsPrincipal)?.FindFirst(ClaimTypes.NameIdentifier)?.Value; TodoItem current = await InsertAsync(item); return CreatedAtRoute("Tables", new { id = current.Id }, current); } // DELETE tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959 public Task DeleteTodoItem(string id) { return DeleteAsync(id); } } }
そして、マイグレーションを実行します。以下のコマンドをパッケージマネージャーコンソールでたたきましょう。
Add-Migration AddUserId
こんな感じのファイルが作られます。
namespace SampleMobileApp.Migrations { using System; using System.Data.Entity.Migrations; public partial class AddUserId : DbMigration { public override void Up() { AddColumn("dbo.TodoItems", "UserId", c => c.String()); } public override void Down() { DropColumn("dbo.TodoItems", "UserId"); } } }
いい感じですね。ついでに、自動でマイグレーションしてくれるようにしましょう。
App_Startの下のStartup.MobileApp.csにあるMobileServiceInitializer
を以下のように書き換えます。
class MobileServiceInitializer : MigrateDatabaseToLatestVersion<MobileServiceContext, SampleMobileApp.Migrations.Configuration>
{
}
これで自動でマイグレーション走るようになります。これが嫌なケースの場合は、別途マイグレーションのSQLを生成する方法を最初に示したマイグレーションについて書かれたページで参照してみてください。
発行して実行すると以下のようになります。
何も違いがわかりませんね。なかなか複数アカウント持ってないので確認しづらいところではあります…。ということで、DBを見てみましょう。
UserId列が追加されて、値が入ってますね!!そして、DBにいろいろ値が入ってるけどちゃんとフィルタリングした結果が出てるっぽいですね!やったね!