.NET > Code First Programming Model > CTP4


※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

コードの実装と実行(サンプルプロジェクト)

ADO.NET開発チームのブログに投稿されているブログエントリにサンプルプロジェクトのアーカイブがあります。このサンプロプロジェクトにはプロジェクトをビルドするために必要なライブラリ(CTP4)が含まれていないので、別途CTP4を入手してプロジェクトへ参照設定を行ってください。

何も設定しない場合は、ローカル環境からSQLServerを探し、そこにデータベースを作成します。
ローカル環境にSQLServerが存在しない場合は、例外をスローしアプリケーションは終了します。

次のようにDatabase.DefaultConnectionFactoryにSQLCEへ接続するためのファクトリを設定すれば、SQLCEを使用してデータベースを作成することができます。(SQLServerを入れる必要がないので、ちょっと使ってみたい方はこちらがオススメ)
ただし、VS2010のSQLCE3.5であるため、CTP4からアクセスすることはできません。別途、SQLCE4をインストールしなければなりません。(Microsoft SQL Server Compact 4.0)

このコードをビルドするにはCTP4の他に次のライブラリを参照設定に加えます。

  • System.ComponentModel.DataAnnotations.dll
  • System.Data.Entity.dll
class Program
{
    static void Main(string[] args)
    {
    	// SQLCEを使う場合は、
    	// 適切なデータプロバイダ名を入れたSqlCeConnectionFactoryをファクトリに設定する。
		Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
 
        Database.SetInitializer<ProductCatalog>(new RecreateDatabaseIfModelChanges<ProductCatalog>());
 
        using (var context = new ProductCatalog())
        {
            // Use Find to locate the Food category
            var food = context.Categories.Find("FOOD");
            if (food == null)
            {
                food = new Category { CategoryId = "FOOD", Name = "Foods" };
                context.Categories.Add(food);
            }
 
            // Create a new Food product
            Console.Write("Please enter a name for a new food: ");
            var productName = Console.ReadLine();
 
            var product = new Product { Name = productName, Category = food };
            context.Products.Add(product);
 
            int recordsAffected = context.SaveChanges();
 
            Console.WriteLine(
                "Saved {0} entities to the database.", 
                recordsAffected);
 
            // Query for all Food products using LINQ
            var allFoods = from p in context.Products
                            where p.CategoryId == "FOOD"
                            orderby p.Name
                                select p;
 
            Console.WriteLine("All foods in database:");
            foreach (var item in allFoods)
            {
                Console.WriteLine(" - {0}", item.Name);
            }
 
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }
    }
}
 
public class Category
{
    public string CategoryId { get; set; }
    public string Name { get; set; }
 
    public ICollection<Product> Products { get; set; }
}
 
public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
    public string CategoryId { get; set; }
 
    public Category Category { get; set; }
}
 
public class Supplier
{
    [Key]
    public string SupplierCode { get; set; }
    public string Name { get; set; }
}
 
public class ProductCatalog : DbContext
{
    public ProductCatalog()
        : base("MyData" )
    { }
 
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Supplier>().Property(s => s.Name).IsRequired();
    }
 
    public DbSet<Category> Categories { get; set; }
    public DbSet<Product> Products { get; set; }
    public DbSet<Supplier> Suppliers { get; set; }
}

実行結果は次の通り。
途中で「ポテトチップス」と入力しました。入力した名前を持つProductエンティティが作成され永続化されます。

「All foods in database:」の次の行からはデータベースの中身を列挙しています。

何回か実行してみると、データベースに永続化されたデータが列挙されます。

データベースの場所

SQLCEは1つのデータベースを1つのファイルで保存します。
このサンプルでは、実行ファイルと同じディレクトリにMyData.sdfというファイルが作成されていることが確認できます。

デバッグ実行をしても値が記録されているのはこのファイルがプロジェクトのソリューションフォルダ内の「bin/Debug(または、bin/Release)」にSQLCEデータベースファイルがあるためです。
永続化したデータを初期化したい場合は、このファイルを削除してからリビルドする必要があります。

データベースの中身を確認

データベースにSQLCE4を使用している場合は、SQLCE4用のデータベースビューワーが別途必要です(VS2010のデータベースエクスプローラーはSQLCE3.5までしか対応していない)
下記のサイトからSQLCE4で作成したデータベースファイルを表示するソフトをダウンロードすることができます。

規約

一度実行されると自動的にデータベースが作成されそこにテーブルが作成されます。

データベースが作成された後に、エンティティモデルが変更された場合、自動的にその変更はデータベースへ適応されます。
このように規約が変更された場合の変更は、

Database.SetInitializer(new RecreateDatabaseIfModelChanges());

の呼び出しでデータベースへ適応されます。

多くの設定は規約により初期設定が定義されています。(規約についてはこちらのブログポストも参照)

  • 主キーの規約
  • 外部キーの規約
  • 逆関連設定
  • 複合型の使用

プログラマが任意にこれらの規約を再設定したい場合はアノテーションを使用します。

主キーの規約

ブログポストを引用しています。

Previously Code First would infer that a property is a primary key if the property is called ‘Id’ or ‘<class name>Id’.
The only change to this convention is that once primary key properties are detected if their type is ‘int’, ‘long’ or ‘short’, they 
are registered as identity columns in the database by default. Primary key detection is not case sensitive.

この記述にもあるように、モデルクラスのプロパティで「Id」もしくは「クラス名+Id」という名前を主キーとします。

外部キーの規約

インスタンスとしての参照先のクラスに主キーとなるプロパティが存在する場合は、外部キーに相当するプロパティをクラス定義に記述することをしなくても自動的に外部キーを作成しマッピングします。

public class Person
{
	[Key]
	public virtual Int32 PersonId{get;set;}
 
	public virtual string Name{get;set;}
}
 
public class Student
{
	public virtual Int32 StudentId{get;set;}
 
	// 外部キーによって結びつけられるインスタンス
	public virtual Person Person{get;set;}
}

複合型の使用

主キーがない型がエンティティモデルに設定されている場合、それは外部キーによる参照制限ではなく複合型としてマッピングされます。

public class Person {
	public int PersonId { get; set; }
 
	// Nameクラスは主キーが定義されていないので
	// このフィールドは関連としてではなく複合型でマッピングされる
	public Name Name { get; set; }
}
 
// Keyアノテーションを使って主キーを定義していないクラス
public class Name {
	public string Title { get; set; }
	public string FirstName { get; set; }
	public string LastName { get; set; }
}

データアノテーション

プログラマによってマッピングの設定を任意に行うことができます。
これは規約をオーバーライドすることができます。

いくつかのアノテーションは.NET Frameworks4に含まれているもので「System.ComponentModel.DataAnnotations.dll」に含まれています。
プロジェクト内でアノテーションを使用するには、このDLLも忘れずに参照設定へ加えます。

主キーの設定

Keyアノテーションを使って設定します。
コードファーストの規約では主キーはint型やlong型が選択されますが、Keyアノテーションを使うと任意のプロパティを主キーとしてマッピングできます。

public class Person{
	[Key]
	public string PersonId{get;set;}
}

フィールドへの制約を設定

StringLength [StringLength(255)] 文字列型に対して格納可能な文字数を制限する
ConcurrencyCheck
Required [Required(1)] NULL値を許容しないか。
Timestamp
DataMember

関連設定

2つのモデル間で外部キーと主キーが規約によって見つけることができる場合には、関連設定を記述する必要はありません。
次の例は主キー(SSN)と外部キー(AuthorSSN)が規約とは異なるため、RelatedToアノテーションで明示しています。

public class Book {
	[Key]
	public string ISBN { get; set; }
 
	[StringLength(256)]
	public string Title { get; set; }
 
	public string AuthorSSN { get; set; }
 
	[RelatedTo(RelatedProperty=“Books”, Key=”AuthorSSN”, RelatedKey=”SSN”)]
	public Person Author { get; set; }
}
 
public class Person {
	[Key]
	public string SSN { get; set; }
 
	[StringLength(512)]
	public string Name { get; set; }
 
	[RelatedTo(RelatedProperty=”Author”)]
	public ICollection<Book> Books { get; set; }
}

読んでいる本


Effective C#

QLOOKアクセス解析

ここを編集