【译】第5节---Code First约定

原文:http://www.entityframeworktutorial.net/code-first/code-first-conventions.aspx

我们在上一节中已经看到了EF Code-First如何从领域域类创建DB表。 在这里,我们将了解默认的Code-First约定。

 

什么是约定?

约定是一组默认规则,用于在使用Code-First时自动配置基于领域域类定义的概念模型。 Code-First约定在System.Data.Entity.ModelConfiguration.Conventions命名空间中定义。

让我们看看各种Code-First约定的概述。

 

类型发现

在上一节中,我们为想要成为模型的一部分的类创建了一个具有DbSet属性的上下文类。 Code-First将为包含为DbSet属性的类创建表,正如我们在上一节中所看到的那样。

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

以下是一个上下文类,不包括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不被包含在上下文类中的实体集中,Code-First将包含在概念模型中,并为其创建一个DB表,如下所示。

即使上下文类只包含基类作为DbSet属性,Code-First也包括派生类。

类型发现的约定是:

  1. Code-First包括在上下文类中定义为DbSet属性的类型。
  2. 代码首先包括实体类型中包含的引用类型,即使它们在不同的程序集中定义。
  3. Code-First包括派生类,即使只将基类定义为DbSet属性。

 

主键约定

在上一节中,我们已经看到Code-First在每个表中自动创建一个主键。

主键的默认约定是,如果属性名称为Id或<ClassName> Id(不区分大小写),则Code-First将为属性创建一个主键。

主键属性的数据类型可以是任何东西,但是如果主键属性的类型是数字或GUID,则它将被配置为标识列。

如果您定义了除Id或<ClassName> Id以外的键属性,那么将抛出ModelValidationException。 例如,考虑以下标准(Standard )类:

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

像上面的代码中看到的那样,Standard类定义了StdId 键属性。 实体框架将抛出以下异常:

'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将其配置为主键。 我们将在后面的教程中看到如何做。

 

关系约定

Code-First使用导航属性推断两个实体之间的关系。导航属性可以是简单的引用类型或集合类型。

例如,我们在Standard类中定义了标准导航属性,并在Standard类中定义了ICollection <Student>导航属性。 因此,Code First通过在Students表中插入Standard_StandardId外键列,自动创建标准和学生DB表之间的一对多关系。

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外键创建了以下关系:

因此,关系的默认代码第一约定自动插入带有导航属性名称_导航属性类型的主键名称的外键。比如:Standard_StandardId。

 

外键约定

上面已经看到,当遇到导航属性时,Code First会自动插入一个外键。建议在关系的从属结尾附加一个外键属性。 请考虑以下示例:

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,它是Standard类中的key属性。

现在,Code First将在Students类中创建StandardId列,而不是Standard_StandardId列,如下所示:

请注意,在上图中,StandardId外键不为空。 这是因为int数据类型不可空。

Code First首先根据外键的可空性来推断关系的多样性。如果属性为空,那么该关系将被注册为null。 否则,该关系注册为NOT NULL。

将StudentId属性的数据类型从int修改为上面的Student类中的Nullable <int>,以在“学生”表中创建一个可空的外键列。

 

复杂类型约定

Code First为不包含key属性,并且还没有使用DataAnnotation或Fluent API注册主键的类创建复杂类型。

 

默认Code First约定

下面列出了Code First的默认约定:

1.表名:实体类名称+“s”

2.主键:id或类名+id(不区分大小写)

3.外键:默认情况下,EF将查找与主体实体主键名称相同名称的外键属性。如果不存在,则会创建外键为:导航属性_实体主键名称。(见上文示例)

4.可空列:所有引用类型和可空类型(nullable )

5.不可空列:主键和不可空列

6.数据库列顺序:按照实体类的顺序创建,主键会移动到第一个位置

7.属性映射到数据库:默认所有的属性都会映射到数据库,可以使用[NotMapped]特性进行排除

8.级联删除:所有关系类型默认开启

 

下表列出了C#数据类型映射到SQL数据类型,和主键列数据类型和长度:

C# DataTypeRelated DB Column DataTypePK 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+为应用程序定义自定义约定。

posted @ 2017-07-03 16:41  talentzemin  阅读(179)  评论(0编辑  收藏  举报