在EF实体框架之CodeFirst二中也提到数据库里面一般包括表、列、约束、主外键、级联操作、实体关系(E-R图)、存储过程、视图、锁、事务、数据库结构更新等。前面几篇博客把表、存储过程、视图这些算是总结了一下,这篇的话主要总结下基本的约定类型。
1.主键
在数据库中主键是必不可少的,一般主键有业务主键和逻辑主键,而且主键有的还是联合主键在code first中也可以通过约定的形式映射到数据库——[Key]。
[Key] public int ProductID { get; set; }
默认主键约束:属性名为[ID]或[类名 + ID]而且是整数int类型。对于int类型的主键默认是自增的,但有时候不想自增长,可以通过以下方式进行取消自动增长。
[Key] [DatabaseGenerated(DatabaseGeneratedOption.None)] public int ProductID { get; set; }
DatabaseGeneratedOption 有三个选项:
- DatabaseGeneratedOption.Computed: 在用 Code First 生成数据库的时候你可以在 byte 或 timestamp 列上使用 DatabaseGenerated Annotation,否则就应该在数据库存在的情况下使用因为如果数据库不存在,此时 Code First 不知道为计算列(Computed Column)选择使用什么样的公式
- DatabaseGeneratedOption.Identity: 如果主键为 integer 型,则数据库默认为自增长(效果等同于设置DatabaseGeneratedOption.Identity), 如果主键是 GUID 类型,则要显式设置自增长
- DatabaseGeneratedOption.None: 如果不想自增长,可设置成 DatabaseGeneratedOption.None
[Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid ProductID { get; set; }
对于联合主键,就不能使用约定了,要使用Fluent API。
modelBuilder.Entity<Product>().HasKey(t=>new { t.ProductID,t.CategoryID});
2.列名
可以使用[Column]来指定列名以及映射到数据库的数据类型。
[Column("Remark", TypeName ="text")] public string Remark { get; set; }
modelBuilder.Entity<Product>().Property(t => t.Remark).HasColumnName("Remark").HasColumnType("text");
3.数字类型长度及精度
对于decimal类型的数据,经常会保留几位小数,decima(8,2)这样子,在Data Annotation不支持该设置,需要通过Fluent API进行设置。
modelBuilder.Entity<Product>().Property(t => t.UnitPrice).HasPrecision(18, 2);
4.长度、数据类型及是否可空
在默认情况下,int类型的属性生成的列名对应SQL SERVER列int类型;而String类型的属性则对应SQL SERVER列的NVARCHAR类型。若类的字符串类型属性未设置MaxLength,则生成对应的列类型为NVARCHAR(MAX)。如果想限制字符串的长度可以通过使用MaxLength(最长字符长度)、MinLength(最短字符长度)、StringLength(字符长度)来约定。用Required来标识,还可以设置是否可允许空字符串,显示错误消息等。
[Column("Remark", TypeName ="text")] [Required,MaxLength(100),MinLength(20)] public string Remark { get; set; }
[StringLength(6)] public string PassWord { get; set; }
上面约定Remark最短20,最长100.但在Fluent API中并没有MinLength,只有MaxLength。
5.Unicode编码
对于string类型的默认都是映射成navrchar类型,如果想映射为varchar类型可以使用Fluent API的IsUnicode()设置。
modelBuilder.Entity<Product>().Property(t => t.Remark).IsRequired().IsUnicode().HasColumnName("Remark").HasColumnType("text");
6.忽略映射NotMapped
如果哪天想去掉一个属性不想映射到数据库,如果直接注释掉,那可能在其他调用的地方就会报错,没有这个属性,这时可以使用NotMapped,忽略映射到数据库,这样也不会报错。同样对于表也是。
[NotMapped] public string ProductName { get; set; }
[NotMapped] public class Product
modelBuilder.Entity<Product>().Ignore(t=>t.ProductName);
modelBuilder.Ignore<Product>();
7.Timestamp 和ConcurrencyCheck
这两个约定都是为了并发控制,Timestamp 在类中只能存在一个,而ConcurrencyCheck是针对类中的一个或多个属性。关于并发控制,这个会在以后详细总结。
[Timestamp] public Byte[] TimeStamp { get; set; }
[Column("Remark", TypeName ="text")] [ConcurrencyCheck, Required,MaxLength(100),MinLength(20)] public string Remark { get; set; }
8.其他
复杂数据类型这个会放在下一篇博客中讲解。关系特性:InverseProperty和ForeignKey会在关系映射中讲解。
9.使用上面的约束映射了几个比较特殊的到数据库。