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

 

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM