Entity Framework Code First 系列 3——约定及配置
在上一节中我们讲解了一个简单的entity framework application。在这一节里我们将使用Data annotation 和 Fluent API 进行 实体模型的配置。这里我们主要讲解的是通过Fluent API 来进行配置,因为相对于Data Annotation 我更喜欢这种干净的代码而且实体代码是自动生成的使用Fluent API的方式更加灵活和方便。
1. Length ——主要描述数据的长度
Data Annotation
MinLength(nn)
MaxLength(nn)
StringLength(nn)
FluentAPI
Entity<T>.Property(t=>t.PropertyName).HasMaxLength(nn)
继续上一节中示例,对于SchoolName 或 StudentName 之内的字段我们要对它的长度进行约定此时我们就可以通过配置来完成。
采用Data Annotation 的方式,在之后的例子中我将不再采用此种方式。
[MaxLength(100)] public string SchoolName { get; set; }
现在我们来讲解我们的重点 Fluent API
新建一类文件继承EntityTypeConfiguration<Ttype> 泛型类
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel.DataAnnotations; 4 using System.Data.Entity.ModelConfiguration; 5 using System.Linq; 6 using System.Text; 7 8 namespace Stephen.Sample.AEF.CodeFirstSample.Domain.DBConfiguration 9 { 10 public class StudentConfiguration:EntityTypeConfiguration<Student> 11 { 12 public StudentConfiguration() 13 { 14 Property(n => n.StudentName).HasMaxLength(10); 15 Property(n => n.StudentName).HasColumnType("varchar"); 16 Property(n => n.StudentName).IsRequired(); 17 } 18 } 19 }
在Context类中重写OnModelCreateing 方法将StudentConfiguration 类注册。
1 public class SchoolDbContext : DbContext 2 { 3 public DbSet<School> Schools { get; set; } 4 public DbSet<Classroom> Classrooms { get; set; } 5 public DbSet<Student> Students { get; set; } 6 7 protected override void OnModelCreating(DbModelBuilder modelBuilder) 8 { 9 modelBuilder.Configurations.Add(new StudentConfiguration()); 10 modelBuilder.Configurations.Add(new AddressConfiguration()); 11 } 12 }
现在我们将之前的测试代码中student的name的长度改的稍微长一点,再来看一下:
果然没有通过测试,或者你也可以去数据库再看下我们所定义的长度也相应的发生了变化。
2. DataType ——数据类型
对于student 实体的 StudentName 我们定义的是string类型 自动mapping到数据库后 类型编程了Nvarchar类型,但有时我们想修改这种自动对应的类型此时就要用到DataType
我们在StudentConfiguration中配置
1 public StudentConfiguration() 2 { 3 Property(n => n.StudentName).HasMaxLength(10); 4 Property(n => n.StudentName).HasColumnType("varchar"); 5 } 6 7
在运行单元测试InitSchoolDBTestMethod 得到结果
3. 不可为空和可为空
开发中经常要定义默写字段不可为空,默认情况下除主键外我们的其他属性是可以为空的,要想使之为不可为空可以加上
Property(n => n.StudentName).IsRequired();
4. 定义主键
大家一定很奇快之前我们也没有任何定义主键的代码为什么类似StudentId的字段就被自动定义为主键了,其实在entity framework中对于那些带有Id或实体类名+Id如无特殊指定会默认将这些属性定义为主键。当然你也可以自行定义
HasKey(n=>n.StudentName)
5. Database-Generated Options 数据库生成操作
对于一些主键我们可以选择使用guid或递增种子或者自定义规则,此时我们可以用使用HasDatabaseGeneratedOption的相应枚举来完成.
Property(n => n.StudentId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
6. ComplexType是我们非常常用且重要的类型
回到前面School的例子,现在我们对于学校类中添加一个Adress的Complextype,对于这种ComplexType 在数据库中并不映射成一个表。
在定义好Address类后我们同样需要定义个Configuration类
1 using System; 2 using System.Collections.Generic; 3 using System.Data.Entity.ModelConfiguration; 4 using System.Linq; 5 using System.Text; 6 7 namespace Stephen.Sample.AEF.CodeFirstSample.Domain.DBConfiguration 8 { 9 public class AddressConfiguration : ComplexTypeConfiguration<Address> 10 { 11 public AddressConfiguration() 12 { 13 Property(n => n.City).HasMaxLength(20); 14 } 15 } 16 }
运行测试
数据库中School表中就增加了三个字段但整个数据库并没有Address这个表。