型付きデータセット + テーブルアダプターの抱える問題
データアクセスは、型付きデータセット + テーブルアダプターにずっと頼ってました。でも採用することにためらいを感じ始めました。
複数人で同時に開発すると、コンフリクトが発生します。でも型付きデータセットは、すべてのソースとデザイナのXMLが1ファイルに生成されます。長大で複雑過ぎて、マージなんてとてもできません。
Linq To SQLでもEntity Framework(EF)でも、同じ問題が発生すると思っていたのですが、EF 4.1からコードファーストなるものが提供され、POCO(plain old CLR object。サブクラスではなく、インターフェースも実装していないプレーンなクラスのこと)で、実装できるそうなので、試してみました。
検証環境
VS2012、.NET 4.5
手順
プロジェクトを作成します。
今回はとりあえずコンソールアプリケーションで。
NuGetからEFをインストールします。
-
- メニューの[ツール] - [ライブラリパッケージマネージャー] - [ソリューションのNuGetパッケージの管理]でNuGetを起動
- EFをインストールします。
これだけで、ライブラリのダウンロード、参照設定、App.configの設定まで自動でやってくれます。便利になりましたね。
コードを書きます。
User.cs
POCOクラスです。これを元にテーブルが作られます。
namespace EFCodeFirstSample { public class User { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } }
MyContext.cs
DbContextを継承し、DbSetをプロパティにもつクラスを実装します。
using System.Data.Entity; namespace EFCodeFirstSample { public class MyContext : DbContext { public DbSet<User> Users { get; set; } } }
Program.cs
using System; using System.Linq; namespace EFCodeFirstSample { class Program { static void Main(string[] args) { using (MyContext context = new MyContext()) { // 登録 context.Users.Add(new User() { Name = "Sato Taro", Age = 19 }); context.Users.Add(new User() { Name = "Suzuki Jiro", Age = 20 }); context.SaveChanges(); // 20才以上の名前を取得 var names = context.Users.Where(u => 20 <= u.Age).Select(u => u.Name); foreach (string name in names) { Console.WriteLine("名前:" + name); } } } } }
App.config
接続文字列を設定します。nameにはDbContextを継承したクラスの名前を設定します。
<connectionStrings> <add name="MyContext" providerName="System.Data.SqlClient" ConnectionString="Data Source=(local);Database=MyDB;UserID=sa;Password=***" /> </connectionStrings>
「コードファースト」ですから、やることはこれで全部です。デザイナ作ってません。DB作ってません。SQL書いてません。
実行する。
"名前:Suzuki Jiro"が出力されます。
実行後
作成されたDBの確認
ちゃんと、MyDBと以下のテーブルが作成され、レコードがINSERTされていました。
CREATE TABLE [dbo].[Users]( [Id] [int] IDENTITY(1,1) NOT NULL, [Name] [nvarchar](max) NULL, [Age] [int] NOT NULL, CONSTRAINT [PK_dbo.Users] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH ( PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON ) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
Idがプライマリキーになるのは、規約です。クラスのプロパティ名が"Id"または、クラス名 + "Id"になっていると、自動的に設定されます。(プロパティ名を変えたければ、[Key]属性で、明示的にキーのプロパティを指定することもできます)
発行されたSELECT文の確認
事前にProfilerを起動し、発行されているSELECT文を確認しました。
SELECT [Extent1].[Name] AS [Name] FROM [dbo].[Users] AS [Extent1] WHERE 20 <= [Extent1].[Age]
ちゃんとWHEREが指定され、必要な列だけが取得されています。
課題
NameがNull許可になってしまうのが気に入らないので、方法を調べます。