EF Code First(4)Fluent API - 配置属性/类型

上篇博文说过当我们定义的类不能遵循约定(Conventions)的时候,Code First 提供了两种方式来配置你的类:DataAnnotations Fluent API , 本文将关注 Fluent API.

一般来说我们访问 Fluent API 是通过重写继承自 DbContext 的类中方法 OnModelCreating . 为了便于例示,我们先创建一个继承自 DbContext 的类,以及其它的一些类以便使用

 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; }
    }

Model-Wide Setting

HasDefaultSchema() - Default Schema(EF6 onwards)

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

Custom Conventions(EF6 onwards)

约定配置请参考文章 http://www.cnblogs.com/panchunting/p/entity-framework-code-first-custom-conventions.html

Property Mapping 属性映射

HasKey() - Primary Key

指定属性为主键

// Primary Key
modelBuilder.Entity<OfficeAssignment>()
            .HasKey(t => t.InstructorID);

也可以指定多个属性为联合主键

// Composite Primary Key
modelBuilder.Entity<Department>()
            .HasKey(t => new { t.DepartmentID, t.Name });

HasDatabaseGeneratedOption()

为数字型主键取消数据库生成

// Switching off Identity for Numeric Primary Keys
modelBuilder.Entity<Department>()
            .Property(t => t.DepartmentID)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

HasMaxLength() - Specifying the Length on a Property

指定属性长度

// Specifying the Maximum Length on a Property
modelBuilder.Entity<Department>()
            .Property(t => t.Name)
            .HasMaxLength(50);

IsRequired() - Configuring the Property to be Required

必填字段

// Configuring the Property to be Required
modelBuilder.Entity<Department>()
            .Property(t => t.Name)
            .IsRequired();

Ignore() - Specifying Not to Map a CLR Property to a Column in the Database

忽略

// Specifying Not to Map a CLR Property to a Column in the Database
modelBuilder.Entity<Department>()
            .Ignore(t => t.Budget);

HasColumnName() - Mapping a CLR Property to a Specific Column in the Database

指定列名

// 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"));

HasColumnType() - Configuring the Data Type of a Database Column

指定列类型

// Configuring the Data Type of a Database Column
modelBuilder.Entity<Department>()
            .Property(p => p.Name)
            .HasColumnType("varchar");

Configuring Properties on a Complex Type

在复杂类型(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);

IsConcurrencyToken() - Configuring a Property to Be Used as an Optimistic Concurrency Token

设置乐观并发标记

// Configuring a Property to Be Used as an Optimistic Concurrency Token
modelBuilder.Entity<OfficeAssignment>()
            .Property(t => t.Timestamp)
            .IsConcurrencyToken();

IsRowVersion() - Configuring a Property to Be Used as an Optimistic Concurrency Token

设置乐观并发标记,效果同上

// Configuring a Property to Be Used as an Optimistic Concurrency Token
modelBuilder.Entity<OfficeAssignment>()
            .Property(t => t.Timestamp)
            .IsRowVersion();

Type Mapping类型映射

ComplexType() - Specifying That a Class Is a Complex Type

指定复杂类型

// Specifying That a Class Is a Complex Type
modelBuilder.ComplexType<Details>();

Ingore() - Specifying Not to Map a CLR Entity Type to a Table in the Database

忽略实体类型

// Specifying Not to Map a CLR Entity Type to a Table in the Database
modelBuilder.Ignore<OnlineCourse>();

ToTable() - Mapping an Entity Type to a Specific Table in the Database

映射表名

// 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");

Mapping the Table-Per-Hierarchy (TPH) Inheritance

映射 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"));

Mapping the Table-Per-Type (TPT) Inheritance

映射 TPT

// Mapping the Table-Per-Type (TPT) Inheritance
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<OnsiteCourse>().ToTable("OnsiteCourse");

Mapping the Table-Per-Concrete Class (TPC) Inheritance

映射 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)

映射实体中属性到多张表中

  • 实体 Department 属性 DepartmentID, Name 映射到表 Department;

  • 同时属性 DepartmentID, Administrator, StartDate, Budget 映射到表 DepartmentDetails

// 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");
            });

Mapping Multiple Entity Types to One Table in the Database (Table Splitting)

映射多个实体到一张表:实体 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");

Mapping an Entity Type to Insert/Update/Delete Stored Procedures (EF6 onwards)

映射实体到增、改、更、删 存储过程,详情请参考文章 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