EFCodeFirst模式使用的是约定大于配置的编程模式,这种模式利用默认约定根据我们的领域模型建立概念模型。然后我们也可以通过配置领域类来覆盖默认约定。
覆盖默认约定主要用两种手段:
1.数据注释属性(Data Annotations Attributes)
2.FluentAPI
1.数据注释属性
我们可以给领域类或者类的属性添加数据注释属性来实现覆盖默认约定,其实在MVC webApi中也会经常用到数据注释属性。一个栗子
[Table("StudentInfo",Schema ="MySchool")]//数据库名为MySchool.StudentInfo
public class Student
{
public Student() { } [Key]//默认把Id或者classNameId作为主键。通过[key]可以指定主键,如果是数字类型,默认自增
public int SID { get; set; } [Column("Name",Order=,TypeName="ntext")]//必有项:列名为Name ;非必有项:顺序为1,数据库中类型为ntext(order是从0开始的)
[MaxLength()]
public string StudentName { get; set; } [NotMapped]//不映射到数据库中
public int? Age { get; set; } public string Phone{get{return "";}}//getter,setter有一个不存在,就不会映射到数据库 [Index("IndexName",IsClustered =true ,IsUnique =true)]//索引名为IndexName,是聚集索引和唯一索引,直接使用[index]时索引名为IX_StudentNo,为非聚集索引
public string StudentNo{get;set;}
[Timestamp]//在update操作时,包含在where子句中
public byte[] RowVersion{get;set;}
public int StdId { get; set; }
[ForeignKey("StdId")]
public virtual Standard Standard { get; set; }
}
一些常用的数据注释属性
Key | 数据库中对应列为主键 |
Timestamp |
数据库中对应列为timestamp类型,主要用于解决高并发问题 注:一个类只能用一次,且修饰的属性必须为byte[]类型 |
ConcurrencyCheck | 数据库中对应列进行乐观并发检测,主要用于解决高并发问题 |
Required | 属性不为空,数据中对应列 |
MinLength/MaxLength | 属性和数据库中的最小/最大的string长度 |
StringLength | 属性和数据库中的最小,最大 |
架构属性
Table | 用于实体,配置实体对应的数据库表名和表结构 |
Column | 用于属性,配置属性对应数据库列名,顺序和数据类型 |
Index | 用于属性,配置对应数据库的列为索引 |
ForeignKey | 用于属性,指定属性为一个外键 |
NotMapped | 用于实体/属性,不在数据库中生成映射 |
DataBaseGernerated | 用于属性,设置数据库对应列值的生成,如identity,computed或者none |
2.一些补充
1.复合主键
EF6中通过Key和Column属性可以实现复合主键,一个栗子:
public class Student
{
[Key]
[Column(Order=)]
public int StudentKey { get; set; } [Key]
[Column(Order=)]
public int AdmissionNum { get; set; } public string StudentName { get; set; }
}
数据库如下:
注意:EF core中不支持通过[key]属性来设置复合主键,我们可以通过Fluent API的HasKey()方法来实现。
2.ForeignKey的三种形式
一个栗子:
public class Student
{
public int StudentID { get; set; }
public string StudentName { get; set; } //Foreign key for Standard
public int StandardId { get; set; }
public Standard Standard { get; set; }
} public class Standard
{
public int StandardId { get; set; }
public string StandardName { get; set; } public ICollection<Student> Students { get; set; }
}
在上边的栗子中,没有使用ForeignKey覆盖默认的约定,那么安照默认约定执行:EF找到导航属性Standard,找到Standard的主键为StandardId,正好Student类中有StandardId属性,那么就把StandardId设为外键;如果Student类没有StandardId呢?EF会创建一个外键<导航属性名>_<导航属性主键>,在本例中就是Standard_StandardId。
我们不想使用EF自动创建的外键,而是想把一个属性设置成外键,但是这个属性和导航属性的主键名不一致,我们应该怎么去实现呢?
1.[ForeignKey(导航属性名)] 依赖实体(Student依赖Standard,所以Student是依赖实体)中在我们想设置为外键的属性上指定导航属性
public class Student
{
public int StudentID { get; set; }
public string StudentName { get; set; } [ForeignKey("Standard")]
public int StandardRefId { get; set; }
public Standard Standard { get; set; }
} public class Standard
{
public int StandardId { get; set; }
public string StandardName { get; set; } public ICollection<Student> Students { get; set; }
}
2.[ForeignKey(导航属性名)] 依赖实体中在导航属性上指定属性名
public class Student
{
public int StudentID { get; set; }
public string StudentName { get; set; } public int StandardRefId { get; set; } [ForeignKey("StandardRefId")]
public Standard Standard { get; set; }
} public class Standard
{
public int StandardId { get; set; }
public string StandardName { get; set; } public ICollection<Student> Students { get; set; }
}
3.主实体中在导航属性上指定属性名(不推荐)
ublic class Student
{
public int StudentID { get; set; }
public string StudentName { get; set; } public int StandardRefId { get; set; }
public Standard Standard { get; set; }
} public class Standard
{
public int StandardId { get; set; }
public string StandardName { get; set; } [ForeignKey("StandardRefId")]
public ICollection<Student> Students { get; set; }
}
3.ConcurrencyCheck解决高并发
ConcurrencyCheck属性可以用在领域类的一个或多个属性中,领域类的属性使用它修饰后,数据库中对应的列会启用乐观并发检测。
一个栗子:
public class Student
{
public int StudentId { get; set; } [ConcurrencyCheck]
public string StudentName { get; set; }
}
上边栗子中StudentName使用ConcurrencyCheck注释,EF会在Update时将StudentName添加到where子句中。
using(var context = new SchoolContext())
{
var std = new Student()
{
StudentName = "Bill"
}; context.Students.Add(std);
context.SaveChanges(); std.StudentName = "Steve";
context.SaveChanges();
}
在执行SaveChanges()方法时,执行的Sql命令如下:
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
注意:TimeStamp只能用于byte[]类型,且一个类中只能用一次,而ConcurrencyCheck用于任何数据类型的属性且能在一个类中使用多次。
EF CodeFirst系列(4)--- 数据注释属性的更多相关文章
-
EF CodeFirst系列(6)---配置1对1,1对多,多对多关系
这一节介绍EF CodeFirst模式中的1对0/1,1对多,多对多关系的配置,只有梳理清楚实体间的关系,才能进行愉快的开发,因此这节虽然很简单但是还是记录了一下. 1. 1对0/1关系配置 1. 通 ...
-
EF CodeFirst系列(7)---FluentApi配置存储过程
FluentApi配置存储过程 1.EF自动生成存储过程 EF6的CodeFirst开发模式支持给实体的CUD操作配置存储过程,当我们执行SaveChanges()方法时EF不在生成INSERT,UP ...
-
EF CodeFirst系列(5)---FluentApi
FluentApi总结 1.FluentApi简介 EF中的FluentApi作用是通过配置领域类来覆盖默认的约定.在EF中,我们通过DbModelBuilder类来使用FluentApi,它的功能比 ...
-
Entityframework Code First 系列之数据注释
上一篇<Entityframework Code First 系列之项目搭建>讲了搭建一个Code First的控制台项目.里面有一些内容并没有扩展出来讲,因为篇幅有限.这篇针对上面内容中 ...
-
EF CodeFirst系列(2)---CodeFirst的数据库初始化
1. CodeFirst的默认约定 1.领域类和数据库架构的映射约定 在介绍数据库的初始化之前我们需要先了解领域类和数据库之间映射的一些约定.在CodeFirst模式中,约定指的是根据领域类(如Stu ...
-
3.Code-First 约定(EF Code-First系列)
前面,我们已经了解了Code-First利用领域类,怎么为我们创建数据库的简单示例.现在我们来学习一下Code-First约定吧. 什么是约定 约定说白了,就是基于一套规矩办事,这里就是基于你定义好的 ...
-
EF CodeFirst系列(1)---CodeFirst简单入门
1.什么是CodeFirst 从EF4.1开始,EF可以支持CodeFirst开发模式,这种开发模式特别适用于领域驱动设计(Domain Driven Design,大名鼎鼎的DDD).在CodeFi ...
-
EF CodeFirst系列(3)---EF中的继承策略(暂存)
我们初始化数据库一节已经知道:EF为每一个具体的类生成了数据库的表.现在有了一个问题:我们在设计领域类时经常用到继承,这能让我们的代码更简洁且容易管理,在面向对象中有“has a”和“is a”关系 ...
-
EF CodeFirst系列(9)---添加初始化数据和数据库迁移策略
1.添加初始化数据(Seed) 我们可以在初始化数据库的过程中给数据库添加一些数据.为了实现初始化数据(seed data)我们必须创建一个自定义的数据库初始化器(DB initializer),并重 ...
随机推荐
-
关于MySql全文索引
从 Mysql 4.0 开始就支持全文索引功能,但是 Mysql 默认的最小索引长度是 4.如果是英文默认值是比较合理的,但是中文绝大部分词都是2个字符,这就导致小于4个字的词都不能被索引,全文索引功 ...
-
JavaScript中的作用域链原理
执行环境 作用域链的形成与执行环境(Execution Environment)相关,在JavaScript当中,产生执行环境有如下3中情形: 1 进入全局环境 2 调用eval函数 3 调用func ...
-
HTTP Status 404 - No result defined for action com.hebky.oa.classEntity.action.EntitysAction and result input
在开发中总遇到这个问题,No result defined for action:原因:Action中的属性值为空的时候,Struts2的默认拦截器会报错,但是又找不到input的Result,不能够 ...
-
关于css3中before与after用单冒号还是双冒号的疑虑
在 CSS3 中为了区别伪元素和伪类为伪元素使用了双冒号,因此如果使用了 display 或者 width 等属性时使得显示脱离了原本元素后,建议按照标准双写.
-
第二篇-FPGA学习之RoadMap
古语云:知己知彼,百战不殆.那么既然选择了FPGA之路,欲练此功,必先-- 必先了解清楚,FPGA的特点,FPGA善于/不善于解决什么类型问题,以及FPGA应用的方向,FPGA学习的要素等等. 一.F ...
-
使用 random() 生成礼包码
需求:生成100个游戏礼包码 具体如下 # 1.构造100个5位随机数 listNumA = [] for n in range(100): listNumA.append(random.randin ...
-
CVTE C/C++开发工程师笔试题(一)
问题描述: 字符串组装. 现在需要将一些数据格式不同的数据组装成一个char型字符串输出,数据来源包含一个char型的字符串,一个short型的16进制数据: 举例: 假若定义如下2个变量: 1.ch ...
-
JUC 之 ThreadPoolExecutor 的一些研究
ThreadPoolExecutor 概述:===================================================================== 构造函数: 4个 ...
-
python Gevent – 高性能的Python并发框架
话说gevent也没个logo啥的,于是就摆了这张图= =|||,首先这是一种叫做greenlet的鸟,而在python里,按照官方解释greenlet是轻量级的并行编程,而gevent呢,就是利用g ...
-
Python3.5 学习五
心灵鸡汤电影推荐: 阿甘正传.辛德勒名单.肖申克的救赎.勇敢的心.角斗士.美国丽人.教父.钢琴师.指环王.西雅图不眠夜.廊桥遗梦.可可西里的美丽传说.放牛班的春天.血钻.战争之王.上帝之城.*车站. ...