上篇博文说过当我们定义的类不能遵循约定(Conventions)的时候,Code First 提供了两种方式来配置你的类:DataAnnotations 和 Fluent API, 本文将关注 Fluent API.
一般来说我们访问 Fluent API 是通过重写继承自 DbContext 的类中方法 OnModelCreating. 为了便于例示,我们先创建一个继承自 DbContext 的类,以及其它的一些类以便使用
class="code_img_closed" src="/Upload/Images/2013121918/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('e747de18-fb20-40c9-83c7-ea2e8dd2b194',event)" src="/Upload/Images/2013121918/2B1B950FA3DF188F.gif" alt="" />public class SchoolEntities : DbContext { public DbSet<Course> Courses { get; set; } public DbSet<Department> Departments { get; set; } public DbSet<Instructor> Instructors { get; set; } public DbSet<OfficeAssignment> OfficeAssignments { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { // Configure Code First to ignore PluralizingTableName convention // If you keep this convention then the generated tables will have pluralized names. modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); } } public class Department { public Department() { this.Courses = new HashSet<Course>(); } // Primary key public int DepartmentID { get; set; } public string Name { get; set; } public decimal Budget { get; set; } public System.DateTime StartDate { get; set; } public int? Administrator { get; set; } // Navigation property public virtual ICollection<Course> Courses { get; private set; } } public class Course { public Course() { this.Instructors = new HashSet<Instructor>(); } // Primary key public int CourseID { get; set; } public string Title { get; set; } public int Credits { get; set; } // Foreign key public int DepartmentID { get; set; } // Navigation properties public virtual Department Department { get; set; } public virtual ICollection<Instructor> Instructors { get; private set; } } public partial class OnlineCourse : Course { public string URL { get; set; } } public partial class OnsiteCourse : Course { public OnsiteCourse() { Details = new Details(); } public Details Details { get; set; } } public class Details { public System.DateTime Time { get; set; } public string Location { get; set; } public string Days { get; set; } } public class Instructor { public Instructor() { this.Courses = new List<Course>(); } // Primary key public int InstructorID { get; set; } public string LastName { get; set; } public string FirstName { get; set; } public System.DateTime HireDate { get; set; } // Navigation properties public virtual ICollection<Course> Courses { get; private set; } } public class OfficeAssignment { // Specifying InstructorID as a primary [Key()] public Int32 InstructorID { get; set; } public string Location { get; set; } // When the Entity Framework sees Timestamp attribute // it configures ConcurrencyCheck and DatabaseGeneratedPattern=Computed. [Timestamp] public Byte[] Timestamp { get; set; } // Navigation property public virtual Instructor Instructor { get; set; } }View Code
Model-Wide Setting
从 EF6 开始可以使用 DbModelBuilder 中的方法 HasDefaultSchema 来指定所有的表/存储过程/视图等属于哪一个 database schema
modelBuilder.HasDefaultSchema("sales");
PS 1: 在 EF 之前的版本中默认的 schema 是被 hard-coded 成 "dbo", 唯一改变它的方式是使用 ToTable API
PS 2: 解释一下 database schema, 它就是对诸如表、视图、存储过程等的一种逻辑分组的方式(可以想象成对象的集合),你可以把一个 schema 赋予用户以便他能够访问所有经过授权的对象。Schemas 在数据库中可以被创建并被更新,用户也可以被授权访问它,一个 schema 可以被定义成任意用户拥有,并且 schema 的所有权是可以被转移的。我们可以看一下数据库中的 schema
约定配置请参考文章 http://www.cnblogs.com/panchunting/p/entity-framework-code-first-custom-conventions.html
Property Mapping 属性映射
指定属性为主键
// Primary Key modelBuilder.Entity<OfficeAssignment>() .HasKey(t => t.InstructorID);
也可以指定多个属性为联合主键
// Composite Primary Key modelBuilder.Entity<Department>() .HasKey(t => new { t.DepartmentID, t.Name });
为数字型主键取消数据库生成
// Switching off Identity for Numeric Primary Keys modelBuilder.Entity<Department>() .Property(t => t.DepartmentID) .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
指定属性长度
// Specifying the Maximum Length on a Property modelBuilder.Entity<Department>() .Property(t => t.Name) .HasMaxLength(50);
必填字段
// Configuring the Property to be Required modelBuilder.Entity<Department>() .Property(t => t.Name) .IsRequired();
忽略
// Specifying Not to Map a CLR Property to a Column in the Database modelBuilder.Entity<Department>() .Ignore(t => t.Budget);
指定列名
// Mapping a CLR Property to a Specific Column in the Database modelBuilder.Entity<Department>() .Property(t => t.Name) .HasColumnName("DepartmentName");
MapKey - Renaming a Foreign Key That Is Not Defined in the Model
指定外键名
// Renaming a Foreign Key That Is Not Defined in the Model modelBuilder.Entity<Course>() .HasRequired(c => c.Department) .WithMany(t => t.Courses) .Map(m => m.MapKey("ChangedDepartmentID"));
指定列类型
// Configuring the Data Type of a Database Column modelBuilder.Entity<Department>() .Property(p => p.Name) .HasColumnType("varchar");
在复杂类型(Complex Type)上有两种方式来配置 scalar properties
在 ComplexTypeConfiguration 上调用 Property
// Call Property on ComplexTypeConfiguration modelBuilder.ComplexType<Details>() .Property(t => t.Location) .HasMaxLength(20);
也可以使用点标记法来访问复杂类型上的属性
// Use the dot notation to access a property of a complex type modelBuilder.Entity<OnsiteCourse>() .Property(t => t.Details.Location) .HasMaxLength(20);
设置乐观并发标记
// Configuring a Property to Be Used as an Optimistic Concurrency Token modelBuilder.Entity<OfficeAssignment>() .Property(t => t.Timestamp) .IsConcurrencyToken();
设置乐观并发标记,效果同上
// Configuring a Property to Be Used as an Optimistic Concurrency Token modelBuilder.Entity<OfficeAssignment>() .Property(t => t.Timestamp) .IsRowVersion();
Type Mapping类型映射
指定复杂类型
// Specifying That a Class Is a Complex Type modelBuilder.ComplexType<Details>();
忽略实体类型
// Specifying Not to Map a CLR Entity Type to a Table in the Database modelBuilder.Ignore<OnlineCourse>();
映射表名
// Mapping an Entity Type to a Specific Table in the Database modelBuilder.Entity<Department>() .ToTable("t_Department");
也可以同时指定 schema
// Mapping an Entity Type to a Specific Table in the Database modelBuilder.Entity<Department>() .ToTable("t_ Department", "school");
映射 TPH
// Mapping the Table-Per-Hierarchy (TPH) Inheritance modelBuilder.Entity<Course>() .Map<Course>(m => m.Requires("Type").HasValue("Course")) .Map<OnsiteCourse>(m => m.Requires("Type").HasValue("OnsiteCourse"));
映射 TPT
// Mapping the Table-Per-Type (TPT) Inheritance modelBuilder.Entity<Course>().ToTable("Course"); modelBuilder.Entity<OnsiteCourse>().ToTable("OnsiteCourse");
映射 TPC
// Mapping the Table-Per-Concrete Class (TPC) Inheritance modelBuilder.Entity<Course>() .Property(c => c.CourseID) .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); modelBuilder.Entity<OnsiteCourse>() .Map(m => { m.MapInheritedProperties(); m.ToTable("OnsiteCourse"); }); modelBuilder.Entity<OnlineCourse>() .Map(m => { m.MapInheritedProperties(); m.ToTable("OnlineCourse"); });
映射实体中属性到多张表中
// Mapping Properties of an Entity Type to Multiple Tables in the Database (Entity Splitting) modelBuilder.Entity<Department>() .Map(m => { m.Properties(t => new { t.DepartmentID, t.Name }); m.ToTable("Department"); }) .Map(m => { m.Properties(t => new { t.DepartmentID, t.Administrator, t.StartDate, t.Budget }); m.ToTable("DepartmentDetails"); });
映射多个实体到一张表:实体 Instructor 和 OfficeAssignment 映射到同一张表 Instructor
// Mapping Multiple Entity Types to One Table in the Database (Table Splitting) modelBuilder.Entity<OfficeAssignment>() .HasKey(t => t.InstructorID); modelBuilder.Entity<Instructor>() .HasRequired(t => t.OfficeAssignment) .WithRequiredPrincipal(t => t.Instructor); modelBuilder.Entity<Instructor>().ToTable("Instructor"); modelBuilder.Entity<OfficeAssignment>().ToTable("Instructor");
映射实体到增、改、更、删 存储过程,详情请参考文章 http://www.cnblogs.com/panchunting/p/entity-framework-code-first-insert-update-delete-stored-procedures
PS: 关于TPH, TPT, TPC 以后有时间专门写一篇文章介绍
原文参考:http://msdn.microsoft.com/en-us/data/jj591617