EntityFramework Code-First 簡易教程(二)-------Code First約定


 

  • Code First 約定

  在前一篇中,我們已經知道了EF Code-First怎樣從模型類(domain classes)中創建數據庫表,下面,我們開始學習默認的Code-First約定。

什么是約定?

  約定就是在Code-First模式中自動配置模型類的默認規則,Code-First約定定義在System.Data.Entity.ModelConfiguration.Conventions 命名空間

 

讓我們來看看各種約定的概述

類型發現(Type Discovery):

  在前一篇中,我們創建了一個context類並在其里面添加DbSet<T>屬性,T為我們想要操作的模型類。Code-First會包括任何在這個類中的引用類型,就算這個引用類型的定義在其他不同集合中也是如此。

舉個例子,下面的Student實體類有引用了Teacher類的屬性,然而context並沒有包含Teacher的DbSet屬性。

public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public byte[]  Photo { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }
        
    public Teacher Teacher { get; set; }

    public Standard Standard { get; set; }
}

public class Teacher
{
    public Teacher()
    { 
        
    }
    public int TeacherId { get; set; }
    public string TeacherName { get; set; }
}
     

 

context並沒有包含Teacher的DbSet屬性

namespace EF_Code_First_Tutorials
{
        
    public class SchoolContext: DbContext 
    {
        public SchoolContext(): base()
        {
            
        }
            
        public DbSet<Student> Students { get; set; }
        public DbSet<Standard> Standards { get; set; }
            
    }
}

所以,即使Teacher類沒有被包含在context的一個DbSet中,Code-First依然會創建一個Teachers表,如下圖所示

Entity Framework code-first example

即使context僅包含基類(base class)作為DbSet屬性,Code-First也會包含它的派生類(derived class)

總結,類型發現(type discovery)約定是:

  1. Code-First 包含的類型作為一個DbSet屬性被定義在context類中(Code-First includes types defined as a DbSet property in context class.)
  2. Code-First 包含的引用類型被包含在實體類型中,即使它被定義在不同的集合里(Code-First includes reference types included in entity types even if they are defined in different assembly.)
  3. Code-First 包含了派生類,即使只有它的基類作為DbSet屬性被定義(Code-First includes derived classes even if only the base class is defined as DbSet property.)

 

 

  • 主鍵(Primary Key) 約定

  在上一篇中,我們看見Code-First自動在每張表里創建主鍵。這里的主鍵約定是:Code-First會自動把屬性名稱為Id或者<class name>Id(不區分大小寫)的屬性創建為主鍵,主鍵屬性的數據類型可以是任何類型,但是如果主鍵屬性的類型是數字或者GUID,則會將其定義成一個標識列(identity column)。

  如果你已經定義了鍵屬性是除了Id或者<ClassName>Id的其他名稱,則會拋出一個ModelValidationException異常,考慮如下代碼

public class Standard
{
    public Standard()
    { 
        
    }
    public int StdId { get; set; }
    public string StandardName { get; set; }
    
    public IList<Student> Students { get; set; }
   
    }
 }    

如上所示,Standard類定義了StdId作為鍵屬性,Entity Framework將拋出如下異常:

'System.Data.Entity.ModelConfiguration.ModelValidationException' occurred in EntityFramework.dll
EntityType 'Standard' has no key defined. Define the key for this EntityType.

如果你非要定義StdId作為主鍵,那你必須使用DataAnnotations或者Fluent API去配置它成為主鍵,我們將在后面的章節學習到。

 

 

  • 關系(Relationship) 約定

  Code First使用導航屬性(navigation property)在兩個實體之間推斷關系,導航屬性是一種簡單的引用類型或者集合類型。舉個例子,我們在Student類中定義Standard導航屬性,在Stardard類中定義ICollention<Student>導航屬性,所以Code First可以自動在數據庫中的Standards表和Students表之間創建一對多的關系並在Students表中插入Standard_StandardId外鍵列。

public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public byte[]  Photo { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }
        
    //Navigation property
    public Standard Standard { get; set; }
}

public class Standard
{
    public Standard()
    { 
        
    }
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    //Collection navigation property
    public IList<Student> Students { get; set; }
   
}
  

上面的實體使用Standard_StandardId作為外鍵創建如下關系

Entity Framework code-first example

因此,默認的code first關系約定會自動插入外鍵,用<navigation property Name>_<primary key property name of navigation property type>這種格式,比如 Standard_StandardId

 

  • 外鍵(Foreign key) 約定

我們在上面看到了通過導航屬性,Code Frist可以自動插入外鍵。但這里建議在關系末尾包含一個獨立的外鍵屬性。考慮如下代碼:

public class Student
{
    public Student()
    { 
        
    }
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public byte[]  Photo { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }
        
    //Foreign key for Standard
    public int StandardId { get; set; }

    public Standard Standard { get; set; }
}

public class Standard
{
    public Standard()
    { 
        
    }
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    public IList<Student> Students { get; set; }
   
}
        

正如我們看到的,Student類包含了外鍵StandardId,而StandardId是Standard類的主鍵,現在,Code First將會在Students表中創建一個StandardId列來代替Standard_StandardId列,如下所示

Entity Framework code-first example

注意:StandardId外鍵不能為空,因為int數據類型不可為空

Code First 根據不可為空的外鍵推斷多重關系,除非外鍵屬性為空然后關系被注冊為空,否則,外鍵屬性不為空(NOT NULL)。也可以把Student類StandardId屬性的數據類型從int修改成Nullable<int>來創建一個外鍵可為空的Students表。

 

  • 復雜類型(Complex type) 約定

Code First 給類創建不包含鍵屬性,而且主鍵沒有被注冊的復雜類型,這個時候使用DataAnnotation或者Fluent API。

 

  • 默認Code-First 約定表

Default Convention For Description
Table Name <Entity Class Name> + 's' 
EF will create DB table with entity class name suffixed by 's'
Primary key Name 1) Id 
2) <Entity Class Name> + "Id" (case insensitive) 

EF will create primary key column for the property named Id or <Entity Class Name> + "Id" (case insensitive)
Foreign key property Name By default EF will look for foreign key property with the same name as principal entity primary key name. 
If foreign key property does not exists then EF will create FK column in Db table with <Dependent Navigation Property Name> + "_" + <Principal Entity Primary Key Property Name> 
e.g. EF will create Standard_StandardId foreign key column into Students table if Student entity does not contain foreignkey property for Standard where Standard contains StandardId
Null column EF creates null column for all reference type properties and nullable primitive properties.
Not Null Column EF creates NotNull columns for PrimaryKey properties and non-nullable value type properties.
DB Columns order EF will create DB columns same as order of properties in an entity class. However, primary key columns would be moved first.
Properties mapping to DB By default all properties will map to database. Use [NotMapped] attribute to exclude property or class from DB mapping.
Cascade delete Enabled By default for all types of relationships.

下面的表列出了C#數據類型映射到SQL的數據類型,和主鍵列的數據類型以及長度

C# DataType Related DB Column DataType PK Column DataType & Length
int int int, Identity column increment by 1
string nvarchar(Max) nvarchar(128)
decimal decimal(18,2) decimal(18,2)
float real real
byte[] varbinary(Max) varbinary(128)
datetime datetime datetime
bool bit bit
byte tinyint tinyint
short smallint smallint
long bigint bigint
double float float
char No mapping No mapping
sbyte No mapping 
(throws exception)
No mapping
object No mapping No mapping

這是篇對code first約定的概述,這里的約定也能用DataAnnotation和Fluent API重寫。在EF6.0里,你也可以使用自定義約定。

 

學完這篇,相信大家也對“約定大於配置”這種設計理念也有感知了吧^_^

 

下一篇我們將學習怎樣初始化數據庫,嗯,先睡覺了

 


免責聲明!

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



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