CodeFirst我们在使用的时候,会需要一些配置,通过DataAnnotation特性和Fluent Api两种方法来实现
今天我们就来讲下DataAnnotation特性的使用
EF Code-First提供了一个可以用在领域类或其属性上的DataAnnotation特性集合,DataAnnotation特性会覆盖默认的EF约定。
DataAnnotation存在于两个命名空间里:
System.ComponentModel.DataAnnotations和System.ComponentModel.DataAnnotations.Schema
注意: DataAnnotations只提供了一部分的配置选项,全部的配置选项在Fluent API中。
System.ComponentModel.DataAnnotations 包含的特性:
Attribute | 描述 |
---|---|
Key | 标记一个属性,其将会在关系表中被映射成主键 |
Timestamp | 标记一个属性,其将会在数据库中被映射成一个不为null的tiamestamp(时间戳)列 |
ConcurrencyCheck | 这个属性允许你标记一个或多个属性,被标记的属性将会在用户编辑或删除entity的时候进行并发检查 |
Required | 强制约束,该属性必须有数据,不能为null(同样适用MVC) |
MinLength | 确保数组或字符串长度达到最小长度 |
MaxLength | 数据库中列的长度的最大值 |
StringLength | 在数据字段中指定字符允许的最大长度和最小长度 |
System.ComponentModel.DataAnnotations.Schema 包含的特性:
Attribute | 描述 |
---|---|
Table | 指定被映射的类在数据库生成的表名 |
Column | 指定被映射的属性在表中的列名和数据类型 |
Index | 在指定列上创建索引(仅EF6.1以上版本支持) |
ForeignKey | 给导航属性指定外键属性 |
NotMapped | 标记的属性不会被映射到数据库 |
DatabaseGenerated | 指定的属性将会映射成数据库表中的计算列,所以这个属性应是只读的。也可以用在把属性映射成标识列(自增长列) |
InverseProperty | 当两个类之间包含多重关系的时候,默认约定会排列组合他们的导航属性组合并一一创建外键,InverseProperty可以标记实际的主外键关系,从而过滤掉因排列组合出来的无用外键 |
ComplexType | 标记一个类为复杂类型 |
重要的特性稍微描述下
1.Key
设置表的主键,CodeFirst默认会将带有Id的事整型类型的字段设置成主键,如果我们要自定义那么可以使用Key来实现
[Table("Emp")]//默认约定是以s结尾如Emps生成表
public class Emp
{
[Key]
public string empid { get; set; }
public string empname { get; set; }
public int? age { get; set; }
[ForeignKey("dep")]
public string depid { get; set; }
public string tel { get; set; }
public string duty { get; set; }
public Dep dep { get; set; }
}
这样数据库中就会将empid设置为主键
我们也可以设置混合主键,如
[Table("Emp")]//默认约定是以s结尾如Emps生成表
public class Emp
{
[Key]
[Column(Order=1)]
public string empid { get; set; }
[Key]
[Column(Order=2)]
public string empname { get; set; }
public int? age { get; set; }
[ForeignKey("dep")]
public string depid { get; set; }
public string tel { get; set; }
public string duty { get; set; }
public Dep dep { get; set; }
}
这样数据库中就会出现组合主键了
2.Table
默认情况下CodeFirst约定表名是加s来建的
如上述代码我们不设置
[Table("Emp")]//默认约定是以s结尾如Emps生成表
则数据库中的表明就会是Emps,我们使用了Table特性来配置的话,表明就会是Emp了。
3.Column
默认情况下表的列是跟属性名一样的,也就是说属性为empid则表的列名就是empid
如果我们要将列名特别设置下就可以使用此配置
如:
[Table("Emp")]//默认约定是以s结尾如Emps生成表
public class Emp
{
[Key]
public string empid { get; set; }
public string empname { get; set; }
public int? age { get; set; }
[ForeignKey("dep")]
public string depid { get; set; }
[Column("phone")]
public string tel { get; set; }
public string duty { get; set; }
public Dep dep { get; set; }
}

如上图,因为我们将属性tel特别是指了特性[column("phone")]所以数据库中表的列名为phone
4.ForeignKey
外键设置
[Table("Emp")]//默认约定是以s结尾如Emps生成表
public class Emp
{
[Key]
public string empid { get; set; }
public string empname { get; set; }
public int? age { get; set; }
[ForeignKey("dep")]
public string depid { get; set; }
[Column("phone")]
public string tel { get; set; }
public string duty { get; set; }
public Dep dep { get; set; }
}
[Table("Dep")]
public class Dep
{
[Key]
public string depid { get; set; }
public string depname { get; set; }
public string upid { get; set; }
public string manager { get; set; }
public string assistant { get; set; }
}
上述代码中我们定义了两个模型,人员和部门,n:1的关系,设定了表Dep的主键depid为Emp的外键 系统自动会生成Dep_depid的外键名,当然上述代码不加特性,系统也会自动判断加上外键的。
5.NotMapped
这个比较简单就是不需要进行映射的属性加上此特性就可以了
[Table("Emp")]//默认约定是以s结尾如Emps生成表
public class Emp
{
[Key]
public string empid { get; set; }
public string empname { get; set; }
public int? age { get; set; }
//[ForeignKey("dep")]
public string depid { get; set; }
[Column("phone")]
public string tel { get; set; }
[NotMapped]
public string duty { get; set; }
public Dep dep { get; set; }
}
大家可以看到我们的属性duty就没有生成数据库表中的列
6.ConcurrencyCheck
当EF执行Update语句时,有此特性的字段会进行并发检查
using System.ComponentModel.DataAnnotations;
public class Student
{
public Student()
{
}
public int StudentId { get; set; }
[ConcurrencyCheck]
public string StudentName { get; set; }
}
exec sp_executesql N'UPDATE [dbo].[Students]
SET [StudentName] = @0
WHERE (([StudentId] = @1) AND ([StudentName] = @2))
',N'@0 nvarchar(max) ,@1 int,@2 nvarchar(max) ',@0=N'Steve',@1=1,@2=N'Bill'
go
上述代码执行的时候会对ConcurrencyCheck特性的列进行检查