EF的默认映射以及如何使用Data Annotations和Fluent API配置数据库的映射
I.EF的默认映射
上节我们创建项目,通过定义实体类就可以自动生成数据库,并且EF帮我们自动设置了数据库的主键、外键以及表名和字段的类型等,这就是EF的默认映射。具体分为:
- 数据库映射:Code First 默认会在本地的SQL Expression数据库中建立一个和DbContext的子类的全名相同的数据库,全名指的是命名空间加上类名。当然前面我们在配置文件里指定了要连接的数据库;
- 表映射:Code First 默认会按照类型名复数建立数据表,比如说Destination类对应的表名就叫Destinations;
- 列映射:Code First 默认会按照类中的属性名建立column,它还有默认的数据类型映射习惯,int会映射为interger,string会映射为 nvarchar(max),decimal会映射为decimal(18,2);
- 主键映射:Code First 默认会在类的属性中需找名字为Id或类型名称+Id的int类型的属性作为主键,并且是自增字段。
摘自这里
默认的映射一般只是简单的映射,当然这些都是可以修改的,请往下看。
II.使用Data Annotations和Fluent API配置数据库的映射
Data Annotations翻译过来就是数据注解,是通过直接在实体类的属性上加注类似标签的东西达到对数据库的映射;
Fluent API翻译过来就是流利的API,Fluent API是在DbContext中定义数据库配置的一种方式。要使用Fluent API 就必须在你自定义的继承自DbContext的类中重载OnModelCreating这个方法。
注意:使用Data Annotations必须添加引用:using System.ComponentModel.DataAnnotations; 更具体的引用请参考本章结尾的源码。
实战:
1.Data Annotations:
设置Destination表的Name不为null:
[Required]
public string Name { get; set; }
很简单,直接在属性上加[Required]标注即可;
2.Fluent API:
用Fluent api必须重写OnModelCreating方法,我们在上下文类里重写下OnModelCreating方法并添加不为空的配置:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<CodeFirst.Model.Destination>().Property(d => d.Name).IsRequired();
}
两种方式都可以配置EF对数据库的映射,任选其一就可以了。我更喜欢Fluent API的方式,故放出的demo中Data Annotations也是有的,不过都被注释了。随着开发的深入,有些东西还是必须用Fluent API的方式才能配置出来的。
上面的方法意思就是:先找到需要配置的实体类,然后点Property就是点出属性,=>是lambda表达式的写法,找到Name属性,然后调用IsRequired方法设置不为null。初见这东西肯定不好理解。没事,写法很固定,多写写就熟悉了。
注意:我的类库都修改了默认命名空间,都加了个CodeFirst. 方便区分,其他类库中调用,我也是习惯用完整的命名空间.类库再.实体类来调用。
思考:使用Fluent API方式配置,每次都需要在OnModelCreating方法里写上一行配置,这样一个实体类如果有3个属性需要配置,10个实体类就需要配置30个,那么就得在OnModelCreating方法里写30行,很麻烦且不易维护。
解决办法:注意返回值可以看出modelBuilder的Entity<>泛型方法的返回值是EntityTypeConfiguration<>泛型类。我们可以定义一个继承自EntityTypeConfiguration<>泛型类的类来定义domain中每个类的数据库配置。
ok,我们在DataAccess类库下新建一个继承自EntityTypeConfiguration<>泛型类的DestinationMap类,在构造函数里写上配置:
public class DestinationMap : EntityTypeConfiguration<CodeFirst.Model.Destination>
{
public DestinationMap()
{
Property(d => d.Name).IsRequired();
}
}
需要添加引用:using System.Data.Entity.ModelConfiguration;
这样,以后Destination需要配置的都来这里配置,然后添加到上下文中的OnModelCreating方法即可:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new DestinationMap());
}
其他类的配置也是这样,先添加一个类名+Map的方法(命名随意),然后添加到OnModelCreating方法。
随意配置一些属性,然后跑下程序看生成的数据库:
可见:Name列已经不可空,Description也设置了长度不超过500等等。
注意:如果重新跑程序生成数据库报这个错:
The model backing the 'BreakAwayContext' context has changed since the
database was created. Either manually delete/update the database, or
call Database.SetInitializer with an IDatabaseInitializer instance. For
example, the DropCreateDatabaseIfModelChanges strategy will
automatically delete and recreate the database, and optionally seed it
with new data.
意思就是,当前数据库正在使用中,无法删除再重新生成。这个时候断开数据库连接,再跑下程序就可以了。以后每次配置实体类再重新跑程序都需要断开数据库连接。
不知道大家还记不记得第一篇文章讲的EdmMetadata这个表,EF会自动帮我们生成这个表。这个表是监控实体类变化的,其实是个诟病,每次操作数据库都会发访问这张表的sql到数据库,用sql Profiler跟踪下即可发现如下sql:
2013.08.07补充:感谢园长dudu在回复中(4楼)的纠正,不是每次操作数据库都会发送sql到数据库,只是在EF初始化的时候会发送访问EdmMetadata表的sql到数据库。另推荐dudu的两篇文章供大家阅读:
SELECT TOP (1)
[Extent1].[Id] AS [Id],
[Extent1].[ModelHash] AS [ModelHash]
FROM [dbo].[EdmMetadata] AS [Extent1]
ORDER BY [Extent1].[Id] DESC
补充:sql Profiler是一个监控发送到数据库sql语句的工具。sql server 2008自带,操作简单,如果不会请自行搜索相关资料。如果没有这个工具,那么是数据库版本不对或者数据库装出了问题。sql Profiler这工具后面讲一对一、一对多、多对多的各种操作时会经常使用到,也是我们调试EF语句性能的好帮手:
扩展:我们可以在OnModelCreating方法里添加:
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();//移除复数表名的契约
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();//防止黑幕交易 要不然每次都要访问
同样需要引入新的命名空间:
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Data.Entity.Infrastructure;
第一句是移除复数表名的契约,就是EF默认生成的表名都是实体类的复数形式,有这句,表名就是实体类的名字了,不会再加个s了,当然你也可以通过强大的Fluent API配置这个。
第二句就是移除对EdmMetadata表的访问的,下次再操作数据库,就不会有访问EdmMetadata表的sql了。
注意:如果之前已经有数据库了,那么再加上移除对EdmMetadata表访问的配置再跑程序会报一个NotSupportedException的错:
Model compatibility cannot be checked because the EdmMetadata type was
not included in the model. Ensure that IncludeMetadataConvention has
been added to the DbModelBuilder conventions.
这个时候,我们先把BreakAwayConfigFile数据库分离,然后必须在本地删除掉,再跑程序就可以了。如果不知道sql server的mdf和ldf文件的默认路径,请自行搜索。
结果跑了下程序,的确没有产生对EdmMetadata表访问的sql了,但是sql
Profiler监控到了更多的sql语句被发送到了数据库。当初为了少一个访问EdmMetadata表的sql,结果多了更多的sql,并且如果再次生成数据库还必须要手动分离现有数据库并删除硬盘上的数据库文件。这里使不使用还是有待商量的,暂时注释掉:
//modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
思考:EF小组设计EdmMetadata表肯定有它的道理,移除对其的访问也不一定是科学的。这里仅做学习演示,真正的项目中可能也很少用Code First的方式生成数据库的。至少4.1版本下的EF使用Code First是有缺陷的,每次都会干掉所有数据,这个肯定不合适。后续的版本有数据迁徙的功能能解决这个,我们目前只是学习4.1这个经典的EF版本。
补充:实际开发中还是database First的方式比较主流。
上面只演示了简单的Data Annotations和Fluent API的一些简单配置,其实还有很多,下面列出部分常用,初学者应该都试着敲敲,然后对照着生成的数据库好好学习下如何配置:
部分摘自这里
现在看了可能会头大,仅做了解和方便后期查阅。后续讲一对一、一对多和多对多的关系时反复的手写Fluent API的时候就会很好理解了。
源码:点击下载
http://www.kwstu.com/ArticleView/guandebao_201382485812638
EF的默认映射以及如何使用Data Annotations和Fluent API配置数据库的映射的更多相关文章
- EF里的默认映射以及如何使用Data Annotations和Fluent API配置数据库的映射
I.EF里的默认映射 上篇文章演示的通过定义实体类就可以自动生成数据库,并且EF自动设置了数据库的主键.外键以及表名和字段的类型等,这就是EF里的默认映射.具体分为: 数据库映射:Code First ...
- EF——默认映射以及如何使用Data Annotations和Fluent API配置数据库的映射 02 (转)
EF里的默认映射以及如何使用Data Annotations和Fluent API配置数据库的映射 I.EF里的默认映射 上篇文章演示的通过定义实体类就可以自动生成数据库,并且EF自动设置了数据库 ...
- EF——使用Data Annotations和Fluent API配置数据库的映射配置 02.01(转)
要更改EF中的默认配置有两个方法,一个是用Data Annotations(在命名空间System.ComponentModel.DataAnnotations;),直接作用于类的属性上面;还有一个就 ...
- 使用 Fluent API 配置/映射属性和类型(摘自微软Data Access and Storage)
使用 Fluent API 配置/映射属性和类型 使用实体框架 Code First 时,默认行为是使用一组 EF 中内嵌的约定将 POCO 类映射到表.但是,有时您无法或不想遵守这些约定,需要将实体 ...
- EF使用Fluent API配置映射关系
定义一个继承自EntityTypeConfiguration<>泛型类的类来定义domain中每个类的数据库配置,在这个自定义类的构造函数中使用我们上次提到的那些方法配置数据库的映射. 映 ...
- 使用 Fluent API 配置/映射属性和类型
使用 Fluent API 配置/映射属性和类型 使用实体框架 Code First 时,默认行为是使用一组 EF 中内嵌的约定将 POCO 类映射到表.但是,有时您无法或不想遵守这些约定,需要将实体 ...
- 10.翻译系列:EF 6中的Fluent API配置【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/fluent-api-in-code-first.aspx EF 6 Code-Firs ...
- 使用Fluent API 配置/映射属性和类型
Code First约定-Fluent API配置 使用Fluent API 配置/映射属性和类型 简介 通常通过重写派生DbContext 上的OnModelCreating 方法来访问Code F ...
- EF CodeFirst方式 Fluent Api配置
一.One-to-One Relationship[一对一关系] 两个表之间,只能由一个记录在另外一个表中.每一个主键的值,只能关联到另外一张表的一条或者零条记录.请记住,这个一对一的关系不是非常的普 ...
随机推荐
- 基于GitLab的Code Review教程
一.前言 1.本文主要内容 GitLab Code Review机制说明 Git Workflow 与 Git Code Review Workflow GitLab Code Review 配置说明 ...
- DataPipeline CTO陈肃:从ETL到ELT,AI时代数据集成的问题与解决方案
引言:2018年7月25日,DataPipeline CTO陈肃在第一期公开课上作了题为<从ETL到ELT,AI时代数据集成的问题与解决方案>的分享,本文根据陈肃分享内容整理而成. 大家好 ...
- SQL SERVER 临时数据库 tempdb 迁移或增加文件
临时数据库TempDB 虽然是临时库,但对整个数据库系统性能却起到很关键的作用:平时用到的中间数据集会暂时保存到TempDB 中,比如:临时表,排序,临时统计信息,一些中间结果数据,索引重建 等.我们 ...
- SQL优化小技巧
我们要做到不但会写SQL,还要做到写出性能优良的SQL语句. 1.使用表的别名(Alias): 当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析 ...
- EM算法(Expectation Maximization)
1 极大似然估计 假设有如图1的X所示的抽取的n个学生某门课程的成绩,又知学生的成绩符合高斯分布f(x|μ,σ2),求学生的成绩最符合哪种高斯分布,即μ和σ2最优值是什么? 图1 学生成绩的分 ...
- Core官方DI剖析(1)--ServiceProvider类和ServiceCollection类
前段时间看了蒋老师的Core文章,对于DI那一块感觉挺有意思,然后就看了一下Core官方DI的源码,这也算是第一个看得懂大部分源码的框架,虽然官方DI相对来说特别简单, 官方DI相对于其它框架(例如 ...
- easyui validatebox textbox 取值和赋值
总结:表单元素使用easyui时,textbox和validatebox设置值和获取值的方式不一样 text-box设置值只能使用id选择器选择表单元素,只能使用textbox("setVa ...
- 小A的柱状图
链接 [https://ac.nowcoder.com/acm/contest/549/H] 题意 [] 分析 很显然你必须找到该高度下往左右找到第一个高度比该位置小的.这个区间的宽*该高度.就当前能 ...
- Tutorial 03_分布式数据库HBASE
(一)编程实现一下内容,并用Hadoop提供的Shell命令完成相同任务: 编程实现: (1)列出HBase所有表的相关信息,例如表名; package tutorial01; import java ...
- Vuex 存储||获取后台接口数据
如果你对 Vuex 有一定的了解的话呢,可以继续这一篇的学习了,如果没有的话, 建议先看一看我的上一篇 Vuex基础:地址在下面 Vuex的详解与使用 Vuex刷新数据不丢失 这篇接着上一篇: 这篇将 ...