第十六节: EF的CodeFirst模式通过Fluent API修改默认协定
一. 简介
1. 优先级:Fluent API > data annotations > default conventions.
2. 所有的Fluent API配置都要在 OnModelCreating这个重写方法中进行
3. 常见的配置:
① 获取表对应的配置根: var stu =modelBuilder.Entity<XXX>();
② 设置主键:HasKey<string>(s => s.studentKey);
③ 获取属性:stu.Property(p => p.stuName)
④ 设置可空或非空:IsRequired和IsOptional
⑤ 设置最大值:HasMaxLength
⑥ 修改属性名→修改属性的次序→修改属性对应的数据库类型:HasColumnName→HasColumnOrder→HasColumnType
⑦ 修改表名:ToTable
4. 可以建立多个Fluent API的配置文件,然后通过 modelBuilder.Configurations.Add(new XXX());添加到一起
PS:或者利用这句话 modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly()); 把所有的配置文件一次性全部加进来
二. 代码实战
1 public class Student5 2 { 3 //主键声明 4 public string studentKey { get; set; } 5 6 //非空声明 7 public string stuName { get; set; } 8 9 //最大长度 10 public string stuTxt1 { get; set; } 11 12 //最大长度和最小长度 13 public string stuTxt2 { get; set; } 14 15 //设置为时间戳 16 public byte[] rowVersion { get; set; } 17 18 //并发检查 19 public string stuTxt3 { get; set; } 20 21 //public virtual StudentAddress5 stuAddress5 { get; set; } 22 } 23 public class StudentAddress5 24 { 25 //既是主键、又是外键 26 public string stuAddressId { get; set; } 27 28 //设置映射数据库中表的列名 29 public string stuAddressName { get; set; } 30 31 //设置映射数据库中表的列名、顺序、类型 32 public string stuAddrssName2 { get; set; } 33 34 //不映射数据 35 public string addressNum { get; set; } 36 37 //不映射数据 38 public string txt1 { get { return stuAddrssName2; } } 39 40 //不映射数据 41 public string _txt2 = "1"; 42 public string txt2 { set { _txt2 = value; } } 43 44 //public virtual Student5 stu { get; set; } 45 } 46 47 /// <summary> 48 /// Game实体,与其它两个没有什么直接关系,单纯的为了演示, Fluent API的配置,可以根据实体进行拆分 49 /// 文件来配置,方便管理 50 /// </summary> 51 public class Game 52 { 53 public int GameId { get; set; } 54 55 public string GameName { get; set; } 56 }
1 /// <summary> 2 /// Game实体的配置文件 3 /// </summary> 4 public class GameConfiguration : EntityTypeConfiguration<Game> 5 { 6 public GameConfiguration() 7 { 8 this.HasKey(p => p.GameId); 9 10 this.Property(p => p.GameName).HasMaxLength(10).IsRequired(); 11 } 12 }
1 public class dbContext5 : DbContext 2 { 3 public dbContext5() 4 : base("name=dbContext5") 5 { 6 7 } 8 9 public DbSet<Student5> Student5 { get; set; } 10 11 public DbSet<StudentAddress5> StudentAddress5 { get; set; } 12 13 14 protected override void OnModelCreating(DbModelBuilder modelBuilder) 15 { 16 //所有的FluentAPI均在方法中进行重写 17 18 //一. 属性层次上的设置 19 var stu = modelBuilder.Entity<Student5>(); 20 var stuAddress = modelBuilder.Entity<StudentAddress5>(); 21 22 //1. 设置主键 23 stu.HasKey<string>(s => s.studentKey); 24 stuAddress.HasKey<string>(s => s.stuAddressId); //为什么需要动态设置主键,有待研究?? 25 26 //2. 设置非空 (扩展:IsOptional 设置可空) 27 stu.Property(p => p.stuName).IsRequired(); 28 29 //3. 设置最大值(不能设置最小值) 30 stu.Property(p => p.stuTxt1).HasMaxLength(10); 31 32 33 //4. 修改列的名称、排序、类型 34 stuAddress.Property(p => p.stuAddrssName2).HasColumnName("myAddress2").HasColumnOrder(1).HasColumnType("varchar"); 35 36 //5.修改表名 37 stu.Map<Student5>(c => 38 { 39 c.ToTable("MyStudent"); 40 41 }); 42 43 //6.将一个实体映射成多张表,并分别给其命名 44 //stuAddress.Map<StudentAddress5>(c => 45 //{ 46 // c.Properties(p => new 47 // { 48 // p.stuAddressId, 49 // p.stuAddressName 50 // }); 51 // c.ToTable("MyStuAddress1"); 52 //}).Map<StudentAddress5>(c => 53 //{ 54 // c.Properties(p => new 55 // { 56 // p.stuAddressId, 57 // p.stuAddrssName2 58 // }); 59 // c.ToTable("MyStuAddress2"); 60 //}); 61 62 63 64 65 //三. 将Game实体的配置添加进来 66 modelBuilder.Configurations.Add(new GameConfiguration()); 67 68 base.OnModelCreating(modelBuilder); 69 } 70 }
1 <!--正宗的CodeFirst Fluent API--> 2 <add name="dbContext5" connectionString="data source=localhost;initial catalog=CodeFirstDB5;persist security info=True;user id=sa;password=123456;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" /> 3
三. 总结
无论是DataAnnotation还是Fluent API,都会发现一个现象,当数据库结构发生变化的时候,就会抛出异常,不得不把数据库删除,重新生成,这样就会导致原数据库中的数据丢失,在实际开发中,显然是不可取的。那么为什么会抛异常呢?怎么解决这个数据丢失的问题呢?详见下一个章节:数据库初始化策略和数据迁移。
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。