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列类型之间的阻抗失配的问题。比如,假设你在.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(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 数据库列属性映射
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使用数据注解特性创建表结构的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C# EF Core可视化工具的使用及EF Core入门语句操作代码

    目录 前言 一.EFCoreTools的下载 二.EFCoreTools的使用 1.新建项目并引入EFCoreTools 2.手动引入EFCore的包 三.EFCore的填查删改 1.添加操作 2.查找操作 3.删除操作 4.修改操作 四.总结 前言 Entity Framework (EF) Core 是轻量化.可扩展.开源和跨平台版的常用 Entity Framework 数据访问技术. 一.EF Core Tools的下载 EFCore Tools可视化工具下载后安装,并重启ViusalS

  • 使用EF的Code First模式操作数据库

    EF的核心程序集位于System.Data.Entity.dll和System.Data.EntityFramework.dll中.支持CodeFirst的位于EntityFramework.dll中.通常使用NuGet Package Manager来添加这些程序集. 如果没有数据库: 1.先写代码,自动创建数据库. 2.如果代码有变化,自动删除数据库重建,或者是使用迁移功能更改已有数据库. 如果已有数据库: 使用EF PowerTools反向工程生成模型. 下面的示例程序中将通过一个控制台程

  • EF使用Code First模式给实体类添加复合主键

    using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Web; namespace MyFirstMvcApp.Models { /// <summary> /// 登录记录 /// </su

  • ASP.Net Core基于EF6、Unitwork、Autofac实现Repository模式

    一.实现的思路和结构图 Repository的共同性 有一些公共的方法(增删改查), 这些方法无关于Repository操作的是哪个实体类,可以把这些方法定义成接口IRepository,然后有个基类BaseRepository实现该接口的方法.常见的方法,比如Find, Filter, Delete, Create等 Repository的差异性 每个Repository类又会有一些差异性,应当允许它们能够继承BaseRepository之外,还能够再扩展自己的一些方法.所以每个类都可以再定义

  • EF使用Code First模式生成单数形式表名

    使用Code-First模式生成数据库时,默认生成的数据库表的名称为类型的复数形式,例如实体类名称是"User",默认生成的数据库表名为“Users”,多数情况下我们并不想生成的数据库表名为复数形式,那么应该如何来控制呢? 当我们想要自定义一些数据库表的生成规则的时候,会重写OnModelCreating()方法,控制生成的表名的单复数形式同样可以在这个方法中完成,实现代码如下: using System; using System.Collections.Generic; using

  • EF Core通过显式编译提高查询性能

    今天,我将向您展示这些EF Core中一个很酷的功能,通过使用显式编译的查询,提高查询性能. 不过在介绍具体内容之前,需要说明一点,EF Core已经对表达式的编译使用了缓存:当您的代码需要重用以前执行的查询时,EF Core将使用哈希查找并从缓存中返回已编译的查询. 不过,您可能希望直接对查询进行编译,跳过哈希的计算和缓存查找.我们可以通过在EF静态类中下面两个方法来实现: EF.CompileQuery() EF.CompileAsyncQuery() 这些方法允许您定义一个已编译的查询,然

  • EF使用数据注解特性创建表结构

    一.理解Code First及其约定和配置 传统设计应用的方式都是由下而上的,即我们习惯优先考虑数据库,然后使用这个以数据为中心的方法在数据之上构建应用程序.这种方法非常适合于数据密集的应用或者数据库很可能包含多个应用使用的业务逻辑的应用.对于这种应用,如果要使用EF的话,我们必须使用Database First方式. 设计应用的另一种方法就是以领域为中心的方式(领域驱动设计DDD).DDD是一种由上而下的方式,我们通过从实现应用所需要的领域模型和实体的角度思考,从而开始设计应用.数据库很少用来

  • Entity Framework使用DbModelBuilder API创建表结构

    DbContext类有一个OnModelCreating方法,它用于流利地配置领域类到数据库模式的映射.下面我们以fluent API的方式来定义映射.首先,先将Product类注释掉,重新编写该类,重新编写后的Product类: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EFFluent

  • 用注解编写创建表的SQL语句

    今晚读了think in java 的章节,感觉很不错,我就敲了下来,贴上代码给以后一个回顾: 建议提前读一下think in java 注解 . 说明创建注解我在第一个注解说明下,以后的注解不在说明.' DBTable 注解: /** * Project Name:myannotation * File Name:DBTable.java * Package Name:com.iflytek.db * Date:2016-8-28下午08:20:54 * Copyright (c) 2016,

  • Mybatis自动创建表和更新表结构

    最近有小伙伴问我mybatis有没有自动创建表结构的功能,因为他们之前一直使用hibernate用习惯了,理所当然的认为,在实体类上配置下注解或者写写映射文件,系统启动后就可以自动创建表. 我只能很遗憾的告诉他,mybatis并没有这个功能,看他兴致阑珊的样子,我只能安慰他,就算没有这功能,我们可以自己开发啊~~ 所以就有了下面这套系统,已开源大家可以下来看看~~ Mybatis_BuildTable_V0.2 https://git.oschina.net/sunchenbin/Mybatis

  • 详解 linux mysqldump 导出数据库、数据、表结构

    详解 linux mysqldump 导出数据库.数据.表结构 导出完整的数据库备份: mysqldump -h127.0.0.1 -P3306 -uroot -ppassword --add-locks -q dbname > dbname.sql 说明:--add-locks:导出过程中锁定表,完成后回解锁.-q:不缓冲查询,直接导出至标准输出 导出完整的数据库表结构 : mysqldump -h127.0.0.1 -P3306 -uroot -ppassword --add-locks -

  • InnoDB 类型MySql恢复表结构与数据

    前提:保存了需要恢复数据库的文件 .frm 和 .ibd 文件 条件:InnoDB 类型的 恢复表结构 1.新建一个数据库--新建一个表,表名和列数和需要恢复数据库相同 2.停止mysql服务器 service mysql stop , 3.在/usr/local/mysql/my.cnf 里面添加innodb_force_recovery = 6 4.将需要恢复的表.frm格式文件 覆盖/usr/local/mysql/data/数据库 下的.frm格式文件 5.启动mysql服务器 serv

  • ORCAL 临时创建表与删除表

    目录 一.Orcal临时表分类 1.会话级临时表 2.事务级临时表 二.临时表创建 1.会话级临时表 2.事务级临时表 三.删除临时表 四.删除时报错 1.清空表,然后删除表 2.杀掉进程,然后删除 一.Orcal临时表分类 1.会话级临时表 1).保存一个会话Session的数据. 2).当会话退出时,临时表数据自动清空.表结构与元数据还存储在用户数据字典. 总结:会话级临时表是指临时表中的数据只在会话生命周期之中存在,当用户退出会话结束的时候,Oracle自动清除临时表中数据. 2.事务级临

  • 根据sql脚本修改数据库表结构的几种解决方案

    最近由于项目需要要做一个小工具. 需求:客户用的老库并存储了一些数据,用了一段时间,我们根据客户提出新功能在老库的基础上对新库进行修改.这些修改有很多细节方面的修改,包含存储过程,增加表,修改表字段类型,添加字段. 然后我们自己更新并测试好软件后,需要改动客户那边的老库,老库的数据是要保存的. 解决方案一:很快我就想到用SQL SERVER 08 R2 自带的功能,生成新库脚本.把老库改个名字,跑新库脚本,然后通过数据库自带功能把老库数据导入到新库数据.测试的时候,数据量不大,速度还比较理想.

  • Mysql复制表结构、表数据的方法

    本文给大家分享了好几种复制表结构.表数据的示例介绍,具体详情请看下文吧. 1.复制表结构及数据到新表 CREATE TABLE 新表SELECT * FROM 旧表 这种方法会将oldtable中所有的内容都拷贝过来,当然我们可以用delete from newtable;来删除. 不过这种方法的一个最不好的地方就是新表中没有了旧表的primary key.Extra(auto_increment)等属性.需要自己用"alter"添加,而且容易搞错. 2.只复制表结构到新表 CREAT

  • MYSQL使用.frm恢复数据表结构的实现方法

    我们都知道当我们建立数据表(innodb或myisam)时,会生成相应的文件(如:MYD,MYI,frm) 在这里,我们探讨下使用frm文件恢复 innodb和myisam类型表的结构,不过由于他们存储引擎的特性,所以恢复的方法也不一样,以下是详细的恢复过程. myisamchk "xxx.frm" myisamchk 可以试出来,库是不是 myisam 类型 1:恢复innodb类型数据表结构 我们先从test数据目录 copy一个innodb.frm文件到另外一个库(innodb)

随机推荐