EF使⽤数据注解特性创建表结构
⼀、理解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列类型之间的阻抗失配的问题。⽐如,假设你在中定义了⼀个int类型的属性,那么你就可以认为EF已经安全地处理了这个列的定义并使⽤了合适的类型与之对应。记住⼀些.NET类型和SQL Server列类型之间的映射是很有必要的,下⾯是⼀些最常⽤的映射关系:
SQL Server Database Type.NET Type
Bigint Int64
binary,varbinary Byte[]
Bit Boolean
date,datetime,
DateTime
datetime2,smalldatetime
Datetimeoffset DateTimeOffset
decimal,money
Decimal
smallmoney,numeric
float Double
int Int32
nchar nvarchar,char
String
varchar
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(10,MinimumLength=2)]
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数据库列属性映射
oracle decimal类型NotMapped不要创建对应的字段
Table指定类将映射到的数据库表
ForeignKey表⽰关系中⽤作外键的属性
指定属性应该映射到数据表中计算的列。也可以⽤于映射到⾃动增长的数据库表。DatabaseGenerated
指定数据库⽣成属性值的⽅式(EF不追踪属性的变化)
Required必填字段
MaxLength指定属性中允许的数组或字符串数据的最⼤长度
MinLength指定属性中允许的数组或字符串数据的最⼩长度
StringLength指定最⼩和最⼤字符长度
Range指定数值范围
数据显⽰相关的数据注解:
特性解释
DisplayName指定本地化的字符串(习惯⽤语类)
Display指定本地化的字符串(习惯⽤语属性)
DisplayFormat设置数据字段的格式
ReadOnly指定该特性所绑定到的属性是只读属性还是读/写属性
EditAble指⽰数据字段是否可编辑
HiddenInput指⽰是否应将属性值或字段值呈现为隐藏的 input 元素
ScaffoldColumn指定类或数据列是否使⽤基架
UIHint指定动态数据⽤来显⽰数据字段的模板
其他:
特性解释
DisplayColumn将所引⽤的表中显⽰的列指定为外键列
Description可视化设计器在引⽤组件成员时可以显⽰指定的说明
(命名空间:System.ComponentModel.DescriptionAttribute)
到此这篇关于EF使⽤数据注解特性创建表结构的⽂章就介绍到这了。希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。