Entity Framework(三):使用特性(数据注解)创建表结构
一、理解Code First及其约定和配置
传统设计应用的方式都是由下而上的,即我们习惯优先考虑数据库,然后使用这个以数据为中心的方法在数据之上构建应用程序。这种方法非常适合于数据密集的应用或者数据库很可能包含多个应用使用的业务逻辑的应用。对于这种应用,如果要使用EF的话,我们必须使用Database First方式。
设计应用的另一种方法就是以领域为中心的方式(领域驱动设计DDD)。DDD是一种由上而下的方式,我们通过从实现应用所需要的领域模型和实体的角度思考,从而开始设计应用。数据库很少用来用于领域模型数据的持久化。使用DDD意味着我们要根据每个应用的需求来设计模型和实体,而且模型和实体是数据库可忽略的,即可以使用任何数据库技术实现保存。在这些情景中,我们应该使用EF的Code First方式,因为它允许我们创建POCO(Plain Old CLR Objects)作为持久化可忽略的领域模型。
使用Code First的优势在于:
1、支持DDD。
2、可以早早地着手开发,因为我们不必等待数据库的创建。
3、持久化层(底层的数据库)的改变不会对现有的模型有任何影响。
我们需要搞清楚的第一件事就是约定大于配置的概念。Code First方式期望模型类遵守一些约定,这样的话数据库持久化逻辑就可以从模型中提取出来。比如,如果我们给一个模型定义了一个Id属性,那么它就会映射到数据库中该类所对应的那张表的主键。这种基于约定的方式的好处在于:如果我们遵守了这些约定,那么我们就不必写额外的代码来管理数据库持久逻辑。但这样也存在缺点,缺点在于:如果没有遵守某个约定,那么EF就不会从模型中提取到需要的信息,运行时会抛异常。
在这种没有遵守约定又要持久化数据的情况下,我们需要使用Code First的配置项提供关于模型一些额外的信息。比如,如果我们的模型类中没有Id属性作为主键,那么我们需要在想要的属性上加上[Key]特性,这样它就会被当作主键了。
注意:
EF使用模型类的复数的约定来创建数据表名,创建的列名和该类的属性名是一样的。
示例:
使用在EF应用一:Code First模式中介绍的使用方法创建一个数据库,其中实体类Product定义如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace EFAppointmentCreateTable.Model
{
public class Product
{
public int Id { get; set; } public string ProductName { get; set; } public double ProductPrice { get; set; }
}
}
数据库上下文Context类定义如下:
using EFAppointmentCreateTable.Model;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text; namespace EFAppointmentCreateTable.EFContext
{
/// <summary>
/// 定义数据库上下文类,该类继承自DbContext
/// </summary>
public class Context:DbContext
{
/// <summary>
/// 定义构造函数,继承自父类的构造函数,通过继承父类的构造函数来创建数据库
/// 父类构造函数的参数是配置文件中配置的数据库连接字符串
/// </summary>
public Context()
: base("DbConnection")
{ } //实体属性集合 根据实体名称的复数形式生成数据库的表名
// 生成的表名是Products 和属性名Products无关
// 即使把属性名改成Product,生成的表名还是Products 约定大于配置
public DbSet<Product> Products { get; set; }
}
}
创建后的数据库截图如下:

从上面的截图中可以看出,生成的数据库表名是实体Product的复数形式,使用默认约定生成Id主键列。
二、使用数据注解创建表结构
1、.NET数据类型和SQL数据类型之间的映射
首先EF这个ORM工具就是用来解决.NET类型和SQL Server列类型之间的阻抗失配的问题。比如,假设你在.net中定义了一个int类型的属性,那么你就可以认为EF已经安全地处理了这个列的定义并使用了合适的类型与之对应。记住一些.NET类型和SQL Server列类型之间的映射是很有必要的,下面是一些最常用的映射关系:
| SQL Server Database Type | .NET Type |
| Bigint | Int64 |
| binary,varbinary | Byte[] |
| Bit | Boolean |
| date,datetime, datetime2,smalldatetime |
DateTime |
| Datetimeoffset | DateTimeOffset |
| decimal,money smallmoney,numeric |
Decimal |
| float | Double |
| int | Int32 |
| nchar nvarchar,char varchar |
String |
| real | Single |
| rowversion,timestamp | Byte[] |
| smallint | Int16 |
| time | TimeSpan |
| tinyint | Byte |
| uniqueidentifier | Guid |
完整的映射列表可以参考SQL Server数据类型映射,如果你使用的是其他类型的数据库,你可以在网上自行查找。比如,,如果是Oracle,那么你可以在这里查找:oracle数据类型映射。
2、配置原始属性
以.NET中的string类型的属性开始讨论。SQL Server中的很多类型都会映射到.NET中的string类型,其他主流的RDBMS也是一样的。因此,决定如何存储字符串类型的信息是很重要的,很多关系数据库管理引擎都有多个字符存储类型,他们通常都有以字母N打头的字符类型,这个字母表示要存在这些列中的数据是Unicode数据,基于每个字符以2个字节的格式存储。因此,如果你的数据库中的列存储的是英文的话,就可以使用varchar或者char(可能会加速查询),如果使用的是中文的话,就要使用nvarchar或者nchar。此外,还可以使用带有var的字符类型来指定列的长度是可变的,不使用var的话,字符长度是不可变的。
在EF中有以下几种配置数据库结构的方式,分别是:
1、特性,也叫数据注解。
2、DbModelBuilder API。
3、配置伙伴类。
3、特性(数据注解)
这些特性类都是.NET的一部分,位于System.ComponentModel.DataAnnotaions命名空间下。下面我们修改在上一个例子中使用的Product实体类,修改后的Product实体类如下:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EFDataAnnotations.Model
{
/// <summary>
/// 使用Table特性指定生成的表名
/// </summary>
[Table("Product")]
public class Product
{
//使用Key特性指示该列是主键列
[Key]
//使用Column特性指示生成的数据库表中的列名
[Column("ID")]
public int ProductId { get; set; } /// <summary>
/// StringLength设置数据库表中列的长度
/// 指示ProductName字段的最大长度是10,最小长度是2
/// </summary>
[StringLength(,MinimumLength=)]
public string ProductName { get; set; } public double ProductPrice { get; set; } /// <summary>
/// DataType特性指示生成的数据库表中列的数据类型
/// </summary>
[DataType(DataType.DateTime)]
public DateTime ProductionTime { get; set; } /// <summary>
/// NotMapped特性指示不把该属性映射到数据库表中,即在生成的表中没有d这一列
/// </summary>
[NotMapped]
public decimal d { get; set; }
}
}
运行程序后生成的数据库:

修改代码之后,我们将表的名字使用Table特性全部重新命名成了但是,将Product的主键通过Column特性更改为Id,Key特性指定它是主键,还通过StringLength指定了ProductName列的最大长度为10个字符,最小为2个字符。
此外,数据注解也可以用作验证特性。如果持久化数据时,模型对象的属性值和数据注解所标记的不一致,就会抛异常。
数据验证相关的数据注解:
| 特性 | 解释 |
| Remote | 使用 jQuery 验证插件远程验证程序的特性 |
| FileExtension | 验证文件扩展名 |
| Compare | 比较两个属性的值 |
| RegularExpression | 使用正则表达式验证 |
| CustomValidation | 自定义验证方法 |
| DataType | 指定要与数据字段关联的附加类型的名称 |
| EmailAddress | 电子邮件地址(相当于DataType(DataType.Email)) |
| Phone | 电话(相当于DataType(DataType.Phone)) |
| CreditCard | 信用卡号码(相当于DataType(DataType.CreditCard)) |
| Url | 验证URL(相当于DataType(DataType.Url)) |
| MemberShipPassword | 验证密码字段是否满足成员资格提供程序的当前密码要求 |
数据映射相关的数据注解:
| 特性 | 解释 |
| Key | 主键字段 |
| Column | 数据库列属性映射 |
| NotMapped | 不要创建对应的字段 |
| Table | 指定类将映射到的数据库表 |
| ForeignKey | 表示关系中用作外键的属性 |
| DatabaseGenerated |
指定属性应该映射到数据表中计算的列。也可以用于映射到自动增长的数据库表。 指定数据库生成属性值的方式(EF不追踪属性的变化) |
| Required | 必填字段 |
| MaxLength | 指定属性中允许的数组或字符串数据的最大长度 |
| MinLength | 指定属性中允许的数组或字符串数据的最小长度 |
| StringLength | 指定最小和最大字符长度 |
| Range | 指定数值范围 |
数据显示相关的数据注解:
| 特性 | 解释 |
| DisplayName | 指定本地化的字符串(习惯用语类) |
| Display | 指定本地化的字符串(习惯用语属性) |
| DisplayFormat | 设置数据字段的格式 |
| ReadOnly | 指定该特性所绑定到的属性是只读属性还是读/写属性 |
| EditAble | 指示数据字段是否可编辑 |
| HiddenInput | 指示是否应将属性值或字段值呈现为隐藏的 input 元素 |
| ScaffoldColumn | 指定类或数据列是否使用基架 |
| UIHint | 指定动态数据用来显示数据字段的模板 |
其他:
| 特性 | 解释 |
| DisplayColumn | 将所引用的表中显示的列指定为外键列 |
| Description | 可视化设计器在引用组件成员时可以显示指定的说明 (命名空间:System.ComponentModel.DescriptionAttribute) |
Entity Framework(三):使用特性(数据注解)创建表结构的更多相关文章
- [翻译] - <Entity Framework> - 直接执行数据库命令
原文:[翻译] - <Entity Framework> - 直接执行数据库命令 纯属学习上的记录, 非专业翻译, 如有错误欢迎指正! 原文地址: http://msdn.microsof ...
- 关于Entity Framework采用DB First模式创建后的实体批量修改相关属性技巧
Entity Framework采用DB First模式创建实体是比较容易与方便的,修改已创建的实体在个数不多的情况下也是没问题的,但如果已创建的实体比较多,比如10个实体以上,涉及修改的地方比较多的 ...
- ASP.NET CORE系列【六】Entity Framework Core 之数据迁移
原文:ASP.NET CORE系列[六]Entity Framework Core 之数据迁移 前言 最近打算用.NET Core写一份简单的后台系统,来练练手 然后又用到了Entity Framew ...
- DjangoORM创建表结构以及生成数据库结构
1. ORM的两种 DB first: 创建表结构--根据表结构生成类-----根据类来操作数据库 Code first: 先写代码------再写类----执行命令(一个类生成一个表)当前主流的用法 ...
- MySQL数据库干货分享!mysql每月自动创建表结构
如果你刚好在学MySQL,博主推荐一套很详细的MySQL教程 主要详细讲解了MySQL的相关知识,包括MySQL概述,MySQL应用环境,MySQL系统特性,MySQL初学基础,MySQL管理工具,如 ...
- Oracle数据库之创建表结构
Oracle数据库之创建表结构 主键与外键 主键:关系型数据库中的一条记录中有若干个属性,若其中的某一个属性组(可以是一个属性,也可以是多个)能唯一标识一条记录,那么该属性组就是主键. 外键:关系型数 ...
- sqlserver 复制表结构(可以含有数据 或 只要表结构)
sqlserver 复制表结构(可以含有数据 或 只要表结构) SELECT * INTO bb FROM aa(NOLOCK) WHERE 1=0
- 创建表结构的sql语句
1.创建表结构 表名: ODS_PSP_DIS_DAY_CALC create table ODS_PSP_DIS_DAY_CALC ( ID CHAR(32) NOT NULL, DIS ...
- 【VBA】EXCEL通过VBA生成SQL,自动生成创建表结构SQL
原文:https://blog.csdn.net/zutsoft/article/details/45441343 编程往往与数据库密不可分,一个项目往往有很多的表,很多时候通过excel来维护表结构 ...
随机推荐
- (step6.1.1)hdu 1879(继续畅通工程——最小生成树、kruscal)
题目大意:输入一个整数n,表示有n个村庄.在接下来的n(n-1)/2行中,每行有4个整数begin end weight flag.分别表示从begin到end之间可以连通 ,他们之间的费用为w ...
- Flutter混合栈的管理
Flutter出现的目的旨在统一Android/IOS两端编程,因此完全基于Flutter开发的App,只需提供一个包含FlutterView的页面,后续页面增加/删除/跳转均在FlutterView ...
- TensorFlow编译androiddemo
首先是把tensorflow克隆到本地一份. git clone --recurse-submodules https://github.com/tensorflow/tensorflow.git 既 ...
- JDBC 利用反射技术将查询结果封装为对象(简单ORM实现)
ORM(Object Relational Mapping)对象关系映射 public class ORMTest { public static void main(String[] args) t ...
- 从Intellij IDEA14 SpringMVC4+Hibernate4问题得到的启发
1.在添加model类hibernate注解的时候,idea一直提示没有配置数据源(其实是假报错,浪费我这么长时间,感觉idea还是和vs有很大的差距)! 2.解决上面的问题,又报错,原来id的注解写 ...
- javascript使用parseInt函数时需要注意的一些问题
这个问题大家可能会忽视,我在项目中就遇到了.写了提醒一下大家!!! 在用javascript的parseInt函数时,parseInt("08")或者parseInt(" ...
- 关于分部视图(Partial View)
一.关于分部视图(Partial View) Partial View是可以应用在View中的,编写一次,在其他View中可以被反复使用.通常都是放在"Views——Shared" ...
- unity, copy-paste component
然后到要粘贴的地方,点弹出下拉菜单,如图: 得到:
- (void)0和0的区别及用法
(void)0相当于宏NULL,NULL本身的含义为“空”,在c语言代表“不存在.不确定”的含义. 0不能简单的理解为“没有”的意思,在c语言及二进制中,0和1代表的是“一件事物的正反两个方面“,0是 ...
- Xilinx-7Series-FPGA高速收发器使用学习—RX接收端介绍
上一篇博文介绍了GTX的发送端,这一篇将介绍GTX的RX接收端,GTX RX接收端的结构和TX发送端类似,数据流方向相反,不过和发送端也有一些区别,GTX的RX接收端结构图如图1所示: 图1 下面将根 ...