• Entity Framework Code First (五)Fluent API


      上一篇文章我们讲解了如何用 Fluent API 来配置/映射属性和类型,本文将把重点放在其是如何配置关系的。

      文中所使用代码如下

    复制代码
    public class Student
        {
            public int ID { get; set; }
            public string Name { get; set; }
            public DateTime EnrollmentDate { get; set; }
    
            // Navigation properties
            public virtual Address Address { get; set; }
            public virtual OtherInfo OtherInfo { get; set; }
            public virtual ICollection<Enrollment> Enrollments { get; set; }
        }
    
        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 int CourseID { get; set; }
            public string Title { get; set; }
            public int Credits { get; set; }
    
            // Foreign key
            public int DepartmentID { get; set; }
            public string DepartmentName { get; set; }
    
            public int SomeDepartmentID { get; set; }
    
            // Navigation properties
            public virtual Department Department { get; set; }
            public virtual ICollection<Enrollment> Enrollments { get; set; }
            public virtual ICollection<Instructor> Instructors { get; set; }
        }
    
        public class Instructor
        {
            public int InstructorID { get; set; }
            public string Name { get; set; }
            public DateTime HireDate { get; set; }
    
            // Navigation properties
            public virtual ICollection<Course> Courses { get; set; }
        }
    
        public class Enrollment
        {
            public int EnrollmentID { get; set; }
            public int CourseID { get; set; }
            public int StudentID { get; set; }
    
            // Navigation property
            public virtual Course Course { get; set; }
            public virtual Student Student { get; set; }
        }
    
        public class Address
        {
            public int AddressId { get; set; }
            public string HomeAddress { get; set; }
            public string LiveAddress { get; set; }
    
            // Navigation property
            public virtual Student Student { get; set; }
        }
    
        public class OtherInfo
        {
            public int Id { get; set; }
            public string HomeAddress { get; set; }
            public string MailAddress { get; set; }
            public string PhoneNumber { get; set; }
            public string StudentID { get; set; }
    
            // Navigation property
            public virtual Student Student { get; set; }
        }
    复制代码

    EntityTypeConfiguration<TEntityType>

      上面是泛型类的部分方法截图,一般我们通过 Code First Fluent API 来配置实体间的关系时都是从此泛型类的实例开始,此泛型类为我们提供了大部分的关系处理方法,如必须的 HasRequired ,可选的 HasOptional ,多个的 HasMany .

      上面所有方法(除了 HasMany, HasOptional, HasRequired )的返回值都是泛型类 EntityTypeConfiguration<TEntityType> 的实例本身,这给链式操作提供了极大地方便.

      HasRequired, HasOptional, HasMany 这三个方法的参数都是一个 lambda expression, 只不过前两个用于表示实体关系(Relationship)间的导航属性(navigation property),后一个则是导航属性的集合(Collection

      HasRequired, HasOptional, HasMany 这三个方法的返回值都是可以继续进行配置的泛型类实例,虽然名称不同,方法名也略有不同,但方法主体所体现的思想是一致的

    RequiredNavigationPropertyConfiguration<TEntityType, TTargetEntityType>

    OptionalNavigationPropertyConfiguration<TEntityType, TTargetEntityType>

    ManyNavigationPropertyConfiguration<TEntityType, TTargetEntityType>

      三个泛型类都有类似于如下三个方法 WithRequired, WithOptional, WithMany, 这三个方法都提供了重载的无参版本,有参方法的参数也都是一个 lambda expression, 前两个用于表示实体关系(Relationship)间的导航属性(navigation property),后一个则是导航属性的集合(Collection

      接下来,你可以使用方法 HasForeignKey 继续配置外键属性,方法的参数仍然是一个 lambda expression, 只不过代表一个属性

    DependentNavigationPropertyConfiguration<TDependentEntityType>

    public CascadableNavigationPropertyConfiguration HasForeignKey<TKey>(Expression<Func<TDependentEntityType, TKey>> foreignKeyExpression);

      其它两个类主要包含方法 Map ,如下

    ForeignKeyNavigationPropertyConfiguration

    public CascadableNavigationPropertyConfiguration Map(Action<ForeignKeyAssociationMappingConfiguration> configurationAction);

    ManyToManyNavigationPropertyConfiguration<TEntityType, TTargetEntityType>

    public ManyToManyNavigationPropertyConfiguration<TEntityType, TTargetEntityType> Map(Action<ManyToManyAssociationMappingConfiguration> configurationAction);
    public ManyToManyNavigationPropertyConfiguration<TEntityType, TTargetEntityType> MapToStoredProcedures();
    public ManyToManyNavigationPropertyConfiguration<TEntityType, TTargetEntityType> MapToStoredProcedures(Action<ManyToManyModificationStoredProceduresConfiguration<TEntityType, TTargetEntityType>> modificationStoredProcedureMappingConfigurationAction);

      我们可以继续在返回的实例上进行配置

    CascadableNavigationPropertyConfiguration

    public void WillCascadeOnDelete();
    public void WillCascadeOnDelete(bool value);

      我们看到了级联删除

    Configuring Relationships

    1:1,0 - Configuring a Required-to-Optional Relationship (One-to–Zero-or-One)

      一个学生可以有一个或没有其它信息(包括邮件地址、手机号等)

    // Map one-to-zero or one relationship
    modelBuilder.Entity<OtherInfo>()
        .HasRequired(t => t.Student)
        .WithOptional(t => t.OtherInfo);

    1:1 - Configuring a Relationship Where Both Ends Are Required (One-to-One)

      一个学生肯定有一个地址信息(包含家庭住址、居住地址)

    // Map one-to-one relationship
    modelBuilder.Entity<Address>()
        .HasRequired(t => t.Student)
        .WithRequiredPrincipal(t => t.Address);

    1:N - Configuring a Required-to-Many Relationship (One-to-Many)

      一个学生可以参加多门课程

    // Map one-to-many relationship
    modelBuilder.Entity<Student>()
        .HasMany(t => t.Enrollments)
        .WithRequired(t => t.Student);

    N:N - Configuring a Many-to-Many Relationship (Many-to-Many)

      一个老师可以教授多门课程,一门课程也可以由多名老师教授

    // Map one-to-many relationship
    modelBuilder.Entity<Course>()
        .HasMany(t => t.Instructors)
        .WithMany(t => t.Courses);

      你还可以进一步指定中间连接表(数据库将会创建中间连接表)

    复制代码
    // Map one-to-many relationship
    modelBuilder.Entity<Course>()
        .HasMany(t => t.Instructors)
        .WithMany(t => t.Courses)
        .Map(m =>
        {
            m.ToTable("CourseInstructor");
            m.MapLeftKey("CourseID");
            m.MapRightKey("InstructorID");
        });
    复制代码

    Configuring a Relationship with One Navigation Property - 基于导航属性配置关系

      如果关系是单向的,即两个实体间只在一个实体上定义导航属性。Code First Conventions 能够自动推断这种关系为 one-to-many .

      例如你想在 Student 和 Address 两个实体间建立 one-to-one 关系,而且只在 Address 实体上包含导航属性,此时你就需要用 Code First Fluent API 配置这种关系

    // Map one-to-one relationship
    modelBuilder.Entity<Address>()
        .HasRequired(t => t.Student)
        .WithRequiredPrincipal();

    WillCascadeOnDelete - Enabling Cascade Delete (级联删除)

      你可以使用 WillCascadeOnDelete 来级联删除关系,如果从属主体上的外键是 not nullable, 那么 Code First 将设置级联删除,否则将不会设置级联删除,而只是仅仅把外键设置成 null

       在 Code First Conventions 下是这样移除级联删除的

    modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>()
    modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>()

      Code First Fluent API 的方式如下

    // Cascade Delete
    modelBuilder.Entity<Course>()
        .HasRequired(t => t.Department)
        .WithMany(t => t.Courses)
        .HasForeignKey(d => d.DepartmentID)
        .WillCascadeOnDelete(false);

    Configuring a Composite Foreign Key - 配置组合外键

      如果设置 Department 的主键为组合主键 DepartmentID, Name,则可以通过 Fluent API 为 Course 指定组合外键

    复制代码
    // Composite primary key
    modelBuilder.Entity<Department>()
        .HasKey(d => new { d.DepartmentID, d.Name });
    
    // Composite foreign key
    modelBuilder.Entity<Course>()
        .HasRequired(c => c.Department)
        .WithMany(d => d.Courses)
        .HasForeignKey(d => new { d.DepartmentID, d.DepartmentName });
    复制代码

    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 a Foreign Key Name That Does Not Follow the Code First Convention

      如果从属实体上的外键属性名不符合 Code First Conventions 的规范,意即从属实体上没有外键,你可以通过如下方式来指定

    // Configuring a Foreign Key Name That Does Not Follow the Code First Convention
    modelBuilder.Entity<Course>()
         .HasRequired(c => c.Department)
         .WithMany(d => d.Courses)
         .HasForeignKey(c => c.SomeDepartmentID);

    原文链接:http://msdn.microsoft.com/en-us/data/jj591620

  • 相关阅读:
    Linux系统开发笔记
    软件测试 | Chrome 浏览器+Postman还能这样做接口测试 ?
    yum 在线安装 nginx
    画图3D Paint 3D工作区黑屏
    InfluxDB 存储结构、读、写
    纯前端保存下载文件到本地
    umijs 配置的一些用法和解释 记录
    mongodb在双活(主备)机房的部署方案和切换方案设计
    mongodb oplog详解和格式分析
    麒麟操作系统上安装docker并加载镜像
  • 原文地址:https://www.cnblogs.com/Jeely/p/10954433.html
Copyright © 2020-2023  润新知