ASP.NET含め、Mac上で最低限の.NETアプリが動かせるようになりました。
が、結局の所EntityFrameworkのプロバイダが、事実上SQL Serverにしか対応しておらず※、業を煮やしておりましたが、2015年7月27日にリリースされたbeta6でなんとか使えるようになったということなので早速試してみます。
InmemoryDBやSqliteにも対応をうたっていましたが、事実上動きませんでした(少なくともSqlite版は)。また、MySQLやAzure Tableとかは当分おあずけみたいです。
今回は公開されたサンプルサイトのコードを検証してみたいと思います。
EntityFrameworkを利用したCodeFirstのサンプルです。
結論
動きました!
が、2015年7月30日現在、サンプルサイトの通りやっても動きません。
私が見つけた範囲で、バグが3箇所あり、コードを追加したり、編集したりする必要がありました。
(追記:8月3日現在、コードが修正されているようです)
もちろん、本記事ではちゃんと動くように対応・修正した内容となっています。
環境構築
サンプルサイトの手順通りか、私が以前書いた内容を参考にしてみてください。
ひな形としては、サンプルサイト通り自力で書いても、yeomanを使ってもいいでしょう。yeomanを利用する場合は、Console Applicationを選べばいいです。
前からインストールしている人は、各種環境をbeta6にアップデートする必要があるので、
dnvm upgrade
dnvm list
を実行して、利用環境がbeta6になっていることを確認して下さい。
私の環境では、
Active Version Runtime Arch Location Alias
------ ------- ------- ---- -------- -----
1.0.0-beta5 mono ~/.dnx/runtimes
* 1.0.0-beta6 mono ~/.dnx/runtimes default
となっています。
あと、当然sqliteが必要です。インストールがまだな人はここを参考にインストールしたり、簡単な操作を行えるようにしてみてください。
サンプルコードをなぞってみる
とりあえず作業フォルダは、ConsoleAppとします。
mkdir ConsoleApp
cd ConsoleApp
project.jsonを用意する
プロジェクトに必要な情報を定義する、project.jsonを用意します。
{
"dependencies": {
"EntityFramework.Sqlite": "7.0.0-beta6",
"EntityFramework.Commands": "7.0.0-beta6"
},
"commands": {
"run": "ConsoleApp",
"ef": "EntityFramework.Commands"
},
"frameworks": {
"dnx451": { },
"dnxcore50": {
"dependencies": {
"System.Console": "4.0.0-beta-*"
}
}
}
}
EntityFrameworkの指定は第一階層のdependenciesに設定する必要があります(framework配下にもdependenciesは有りますが)。
この状態で、
dnu restore
を実行し、必要ファイルを取得します。
composer updateみたいなものです。
アプリケーション本体用コード Program.csを用意する
とりあえずHello dnx!とだけ表示する簡単なコードを準備。
// Program.cs
using System;
namespace ConsoleApp
{
public class Program
{
public void Main(string[] args)
{
Console.WriteLine("Hello dnx!");
}
}
}
ひとまず動作を確認する
プログラム
まず、先ほどのC#で書いたコードが正常に実行できるか試します。
dnx . run
project.jsonでConsoleAppのところを変更していない場合はdnx . ConsoleAppとします。
Hello dnx!
と表示されればOKです。
EntiryFrameworkのコマンド
次に、モデルやMigrationファイルの生成に使うEntityFrameworkのコマンド群が機能するかテストしておきます。
dnx . ef
とすると、
_/\__
---==/ \\
___ ___ |. \|\
| __|| __| | ) \\\
| _| | _| \_/ | //|\\
|___||_| / \\\/\\
7.0.0-beta6-13815
Usage: ef [options] [command]
こういう感じのが表示されればOKです。
うまく動かない場合は、project.jsonのdependenciesでEntityFramework.Commandsが設定されているかチェックして下さい。
なお、efという命令はproject.jsonの中の、commandsで定義した名前です。別にefじゃなくてもいいです。
ここからが本題
基本的な動作が確認できたので、DB(EF)を使うコードを書いていきます。
まず、クラスとDBを仲介(情報を提供)したり、Migrationファイル生成の元となるModel.csを作ります。
using Microsoft.Data.Entity;
using System.Collections.Generic;
namespace ConsoleApp
{
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=./blog.db");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public string Name { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
}
一度ビルドしてみる
dnu build --quiet
を事項し、Warning(s)やError(s)が0であることを確認しましょう。
Building ConsoleApp for DNX,Version=v4.5.1
Building ConsoleApp for DNXCore,Version=v5.0
Build succeeded.
0 Warning(s)
0 Error(s)
こんな感じになればOK。
Migrationファイルを作る(バグ1)
efコマンドを利用して、Model.cs情報に基いてテーブルを生成するためのmigrationファイルを生成します。
dnx . ef migration add MyFirstMigration
実行すると、エラーを吐きます。
System.InvalidOperationException: A type named 'StartupProduction' or 'Startup' could not be found in assembly 'ConsoleApp'.
・
・
・
Startupが無いぞ!と怒られているようなので、Statup.csを作成します。
サンプルサイトには、どこにもそんなことは書いていませんが。
using Microsoft.AspNet.Builder;
namespace ConsoleApp
{
public class Startup
{
public void Configure(IApplicationBuilder app)
{
}
}
}
再度、migrationの生成を実行します。
dnx . ef migration add MyFirstMigration
Using context 'BloggingContext'.
Writing migration to '/Users/tamaki/ConsoleApp/Migrations/20150730020129_MyFirstMigration.cs'.
Writing model snapshot to '/Users/tamaki/ConsoleApp/Migrations/BloggingContextModelSnapshot.cs'.
Done. To undo this action, use 'ef migration remove'.
という感じで、Migrationsフォルダが作成され、その下にmigration用のファイルが生成されます。
Migrationしてみる(バグ2)
では、生成されたMigrationファイルを元に、DBを作成してみます。
dnx . ef migration apply
すると、またエラーを吐きます。
Microsoft.Framework.Runtime.Roslyn.RoslynCompilationException: /Users/tamaki/ConsoleApp/Migrations/20150730020129_MyFirstMigration.cs(17,61): DNX,Version=v4.5.1 error CS1503: Argument 2: cannot convert from 'bool' to 'string'
・
・
・
どうやら、xxxx_MyFirstMigration.csで設定されているコードにおいてboolからstringに変換できない!と怒っているようです。
というわけで、xxxx_MyFirstMigration.csのコードを編集します。
BlogテーブルとPostテーブルのIdの設定箇所がおかしいようです。
16行あたりを、
BlogId = table.Column(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
から、
BlogId = table.Column(type: "INTEGER", nullable: false),
と修正します。.Annotation("Sqlite:Autoincrement", true)を削除します。
さらに29行目あたりを同様に修正します。
PostId = table.Column(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
を、
PostId = table.Column(type: "INTEGER", nullable: false),
とします。
再度、migrationを実行します。
dnx . ef migration apply
Using context 'BloggingContext'.
Using database 'main' on server './blog.db'.
Applying migration '20150730020129_MyFirstMigration'.
Done.
Done.となればOKです。
同じ階層にblog.dbファイルが生成されているはずです(Model.csで定義したので)。
DBを利用してみる(バグ3)
Program.csを下記のようにDBを使うように編集します。
URLをDBに書込、それを読みだしているようです。
サンプルコードには簡単な?バグがありましたが、下記は修正済みです。
using System;
namespace ConsoleApp
{
public class Program
{
public void Main(string[] args)
{
using (var db = new BloggingContext())
{
db.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/adonet/hoge" });
var count = db.SaveChanges();
Console.WriteLine("{0} records saved to database", count);
Console.WriteLine();
Console.WriteLine("All blogs in database:");
foreach (var blog in db.Blogs)
{
Console.WriteLine(" - {0}", blog.Url);
}
}
}
}
}
サンプルコードではインスタンス生成はインスタンス名contextとなっているのに、利用時はdbとなっています。
実行してみる
dnx . run
1 records saved to database
All blogs in database:
- http://blogs.msdn.com/adonet/hoge
という感じで、1行表示されています。
一応sqlite側でも確認してみる
sqlite3 blog.db
SQLite version 3.8.5 2014-08-15 22:37:57
Enter ".help" for usage hints.
sqlite>
sqlite> .table
Blog Post __migrationHistory
sqlite> select * from Blog;
1||http://blogs.msdn.com/adonet/hoge
sqlite>
テーブルが作成され、ちゃんと保存されているようです。
最後に
大変でした。
asp.net mvc6からもそのうち試してみたいと思います(やってみました)。
とはいえとりあえずControllerから叩けばいいだけかな。