zoukankan      html  css  js  c++  java
  • Entity Framework Code First (五)Fluent API

    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);
  • 相关阅读:
    《DSP using MATLAB》Problem 6.17
    一些老物件
    《DSP using MATLAB》Problem 6.16
    《DSP using MATLAB》Problem 6.15
    《DSP using MATLAB》Problem 6.14
    《DSP using MATLAB》Problem 6.13
    《DSP using MATLAB》Problem 6.12
    《DSP using MATLAB》Problem 6.11
    P1414 又是毕业季II
    Trie树
  • 原文地址:https://www.cnblogs.com/sjqq/p/7709619.html
Copyright © 2011-2022 走看看