一、参考资料(简介)
本系列,将介绍 实体框架EF(entity framework)。
参考:https://www.cnblogs.com/wangboy91/p/6047905.html
什么是EF框架 ?
全称EntityFramework 官方点的解释是Entity Framework
是ADO.NET
中的一套支持开发面向数据的软件应用程序的技术,是微软的一个ORM框架。
ORM框架是什么东西?
Object Relational Mapping
翻译过来就是对象关系映射。如果你无法理解这个东西。我只能告诉你去百度了。反正我刚开始的也不太明白。下面有个图方便我们理解
在整个领域比较常用的有:Hibernate,iBATIS,mybatis
这些在java生态里面应用的orm框架,这些框架当然也有C#版本的。但是作为微软的亲儿子C# 系列肯定采用EF框架了毕竟强大的linq让我太喜欢了。在ios开发领域中有Core Data
等和安卓的ormlite
等,这些都是orm
框架。
1、官网
https://docs.microsoft.com/zh-cn/ef/
官网里面,包含了最详细最原始的文章,中文博客上的东西,基本都是从官网Copy+变形过来。我们要看,就看最好的,我们要做,就做最好的。
2、中文博客
https://www.cnblogs.com/wdcwy/p/6412944.html
https://www.cnblogs.com/wujingtao/p/5401113.html
https://www.cnblogs.com/xuf22/articles/5513283.html
https://blog.csdn.net/xiongmeiqin/article/details/80196089
二、EF框架的三种模式
DataBase First
数据库优先, 传统的表驱动方式创建EDM,然后通过EDM生成模型和数据层代码。除生成实体模型和自跟踪实现模型,还支持生成轻型DbContext
。简历理解就是先设计数据库,创建好数据库映射成对象和上下文。
Model First
模型优先,先创建EDM
模型,再生成DDL
数据库脚本和模型和数据层代码。除生成实体模型和自跟踪实现模型,支持生成轻型DbContext
。简单理解就是设计EDM
模型然后生成到数据库和创建对象和上下文。
CodeFirst
代码优先,手动创建POCO模型,数据层DbContext
及映射关系,通过Database.SetInitializer
生成数据库,这种方式较灵活,但是需要手动定义实体模型和关系映射。简单理解就是自己写好实体对象和映射关系,最后通过命令生成到数据库中去。
三、Entity Framework应用场景
https://blog.csdn.net/wulex/article/details/79286310
四、Entity Framework的优缺点
转https://blog.csdn.net/wulex/article/details/79286310
Entity Framework是MS提供的一个ORM框架,它旨在为小型应用程序中数据层的快速开发提供便利。
nuget上185W多的下载量,说明.Net开发人员还是比较喜欢用EF的。但是EF在提供了便利性的同时也有许多缺点,以下就是我认为不应该应用EF的场景:
- 非SQL Server数据库且无该数据库的
DataProvider
- 高性能要求。在进行一些复杂查询的情况下,EF的性能表现不太好,而开发人员又无法控制SQL语句的生成
- 高安全性要求。有时候DB用户仅仅具有EXEC的权限,而EF自动生成的类又不好用,还是需要自己来写。
一些大中型企业应用往往具有以上几种情况,此时就不适合使用EF了。
至于使用什么ORM,我个人认为NHibernate
配置起来太麻烦,如果没什么太特殊的要求,可以试一下ServiceStack.OrmLite
能不能满足需求。或者直接上ADO.Net
如果非要使用EF,建议使用EF最新的稳定发布版本(支持DbContext+Code first
方式开发)。然后读一下《Programming Entity Framework Code First》
和《Programming Entity Framework DbContext》
这两本书(目前无中文版)。使用DbContext+Code first POCO+Repository
模式,这样既可以保证EF
被Repository
隔离,又可以保证可测试性,还能在需要更换ORM
框架甚至是换成ADO.Net
时少改一点代码。
提供示例代码下载(.Net 4+EF5)
示例代码中有POCO和EF的Configurations
,把EF相关的Configurations
单独拿出来保证了DB Model
的纯洁性。在这里大体摘一点东西给大家看看
首先是数据库结构,我使用的是Code first
,在第一次有实际的数据库操作的时候会自动生成数据库,生成后的数据库结构如下图:
数据库的生成策略在EFContext
类的静态构造里面:
static EFContext()
{
// 指定数据库生成策略为不存在时生成
// 还可以指定为:
// DropCreateDatabaseAlways(总是删除原有数据库重建)
// DropCreateDatabaseIfModelChanges(数据库模型改变后删除原有数据库重建)
Database.SetInitializer<EFContext>(new CreateDatabaseIfNotExists<EFContext>());
}
Album
表的Configuration
设置:
public class AlbumConfiguration : EntityTypeConfiguration<Album>
{
public AlbumConfiguration()
{
// 指定数据表名
ToTable("dbo.Album");
// 设定主键
HasKey(x => x.Id);
// 设定数据列名及其它属性
Property(x => x.Id).HasColumnName("Id").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).IsRequired();
Property(x => x.AlbumName).HasColumnName("AlbumName").IsRequired().HasMaxLength(50);
Property(x => x.ArtistId).HasColumnName("ArtistId").IsRequired();
// 设置外键约束
HasRequired(foreignKeyTable => foreignKeyTable.Artist)
.WithMany(primaryKeyTable => primaryKeyTable.Albums)
.HasForeignKey(foreignKeyTable => foreignKeyTable.ArtistId);
// 设置多对多关联
HasMany(thisTable => thisTable.Tags)
.WithMany(anotherForeignKeyTable => anotherForeignKeyTable.Albums)
.Map(relationTable => relationTable
.MapLeftKey("TagId")
.MapRightKey("AlbumId")
.ToTable("AlbumTags")
);
}
}
重写EFContext
类中的OnModelCreating
函数,使用我们自定义的Configurations
:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// 设定数据库生成配置
modelBuilder.Configurations.Add(new ArtistConfiguration());
modelBuilder.Configurations.Add(new AlbumConfiguration());
modelBuilder.Configurations.Add(new TagConfiguration());
}
Repository
模式这里我就不多说了,具体看AbstractDbAccessor
项目中的内容,EF的Repository
实现在ConcreteDbAccessor
项目EntityFramework
目录下的EFDbAccessor
和Repository
目录
EntityFramework优缺点
Entity Framework
是微软推荐出.NET平台ORM
开发组件, 现在已放源代码. 以下我们来讨论一下优缺点和一些问题, 以下简称EF
. 有兴趣可查询官网的Entity Framework 6 RoadMap
.
EntityFramework
高层视图:
改变在现有系统使用EntityFramework的优势是什么?
- All -in-1框架的类映射表,需要编写映射代码, 并且是很难维护的。
- 可维护性,易于理解的代码,无需创造大的数据访问层。
- 提供LINQ查询数据库,这需要从初级开发人员不太了解SQL。
- EF可以用作用于数据服务和OData Service的基础设施。
什么的情况下,不建议使用EF呢?
- 实时的应用程序。
- 只能通过存储过程访问数据库。 EF的优势是:跟踪实体状态
Change
时,不仅仅在存储过程上.(即使EF确实对存储过程支持有限的)。 - 频繁插入操作(
Insert
), 并且EF不支持大数据Bulk
插入。 - 频繁更新操作,更新的目标主要是当多行(用一个单值)
例如:UPDATE 表名 SET ColumA = 10 Where ColumnB =?
这种更新操作更好的使用的ExecuteNonQuery
(也可从Context
上下文或直接从Ado.Net
)。
- 反范式的表设计和高性能查询。 EF产生查询,他们是难以维护的,它并不能很好地支持映射到不规范的表。
- 对程序有非常的性能要求, 需要对每个查询进行监控.
我们要在加载所有数据到内存中,建议使用实体框架? 我们应该期待什么样的问题呢?
- 加载的所有实体将需要许多查询和大量的时间。
- 内存开销。
- 会有延迟,因为EF需要跟踪实体的变化的和大
Collection
对象的处理。 - EF的
Context
上下文不是线程安全的,你不应该在整个Service
上使用一个Context
上下文。 - 如果你打算这样做,使用EF加载实体,但并不管理它们. (
Detach the entities
从context
)。 - 不使用的上下文
Context
对象作为一个缓存对象(用于分布式的情况下). 它不是线程安全的,有一些开支和不遵循分散关注(Separation of Concern
)的设计。 更好的办法是设计缓存API
,如AppFabric
缓存。
技术层面:
内存泄漏:
我们有这样一个场景,每10秒我们打开Context
上下文获取一个单表,并关闭它。 “using (entities context = new entities(_connection)) {…
”
经过一段几个小时,这引起了内存泄漏。
- 我建议你检查内存泄漏,以确保它是从EF是根源。 EF是一个开源的,所以现在可以报告任何内存泄漏并修正它。
- 使用
Profiler
的VMMap
,以便跟踪泄漏的源头。
在这种情况下,我们应该保持Context
一直打开?
- 这其实并不重要,因为查询仍然会执行。 然而,这是最好关闭
Context
下,所以缓存的实体将垃圾回收,否则Context
和缓存的实体将在GC
中升级到第二代,并且会被困在那里的持续一段时间。 - 不要为WCF每个请求创建一个Context上下文对象。
- 推荐的做法是为每次操作创建的
Context
对象,因为实体Item
一旦被被添加到数据库后就已经过时了,可能会导致数据损坏或重复的Item
EDMX的大小有影响吗?
EDMX
影响的大小,因为所有的EDMX
数据加载到内存中创建Context
上下文。EDMX
被加载到内存中,解析与映射在AppDomain
中创建和缓存。 您可以关闭并重新打开Context
,它没有影响已缓存EDMX
映射。
非常多的表
如果所有的表放在单个的EDMX
或分别存放于几个EDMX
文件之间?
如何能管理的EDMX
中大量的实体? 例如,如何可以找到它们?
在设计器中修改一个特定的表?
- 如果拆分之间
edmx
文件,你可以不连接实体的导航性能。
你应该建立自己的模型,根据您的实体模型设计 - 如果你有一组是独立的实体,他们可以在不同的EDMX
模型。
EDMX
文件处理数百个实体类型。 如果实体类型的数量超过1000
家,我会考虑到的几个Edmxs
(分开和重新审视自己的实体模型设计,因为成千上万的实体类型的一个系统似乎太多)。 - 在VS 2012,以设计器的增强分解功能和着色等,请参阅以下链接。
EF
设计器有一些改进,如着色区分实体组的实体。
也有第三方实体的设计器,可能会得到更好的用户体验。
请记住 -EF
是一个开源的,你可以给他们的要求,甚至贡献自己的增加,所以在EDMX
设计器探索很有趣的。- 你应该按每个域/服务来拆分
edmx
文件到不同EDMX
文件。
表之间关系
Lazy与No Lazy模式?
- 在分布式情况下
Lazy
代码是魔鬼。 - 如果他们需要一组表中的数据,然后使用
Include
,否则,你可以使用Lazy Load
模式
“Include
”命令加载整个表或ObjectSet
原始记录?
Include
加载是相关实体的列。 EF不使用 * 查询.
如何使用EF执行批量插入/更新操作?
- 做不到这一点,你需要使用原始的SQL语句来实现。
当一个实体被标记为已修改,EF更新的所有列?
- 它不更新所有的列,除非你正在使用分布式的应用程序与
Self-Tracking
。 “正常”实现下EF只更新修改列。Self-Tracking
不跟踪的已更新的属性,它标志着的所有属性已更新。 您可以编辑Self-Tracking
,并修复它,如果需要的话。 - 您可以附加一个
SP
以实现自定义的逻辑。 - 您可以更改T4模板的文件,在
Self-Tracking
下以保持所有原始值。
整个RAW更新的开销大么?
- 大多数DB重新计算索引。 这是一个问题关系到DBA。
当我们使用EF为700-800KB的XML文件来更新XML列,我们收到了有关SQL Server的tempdb
一个异常。 什么造成的吗?
- 可能涉及到数据库如何用临时表来更新
XML
的内容。
应该和DBA检查你的数据库,你也许需要增加您的tempdb
数据库的大小。
- 在一般情况下, 大的对象,如XML使在GC的
Large Object Heap
内存的压力,你应该考虑迁移到.NET 4.5版本的GC大型对象堆碎片整理特性。 - 你可以考虑来存储
XML
为byte []
,它可以被压缩(XML不是一种非常经济的格式)。
使用EF与ADO.Net的开销?
DataReader
的结果变换到对象的开销,从LINQ编译SQL查询的开销。
您将有相同的开销,甚至更多,如果您尝试建立你自己的ORM
框架。 不这样做!
- 抽象层的开销, 它取决于他们用EF所做的事情。
- 一般而言,您应该组合替代继承,避免它有一个更大的开销。
EF优缺点的理解
原先用的是三层架构中ADO.NET做底层开发,纯手工sql
语句拼装。后来遇到一个MVC+EF
项目,体会到了EF的强大性。
它是微软封装好一种ADO.NET数据实体模型,将数据库结构以ORM模式映射到应用程序中。
优点:
-
简洁的
Linq to Sql
语句大大提高了开发人员的效率,不要再写复杂的sql语句; -
不再需要再管应用程序如何去连接数据库;
-
EF可以用作用于数据服务和
OData Service
的基础设施;
缺点:
- 由于
linq
语句编译之后就是sql
,对于这种自动生成的sql
语句无法控制; - EF的运行机制会消耗大量内存,大大降低了程序运行效率,从而导致降低了用户在客户端的体验效果;
- 一旦数据结构发生变化,需要更新EF数据
model
;有时还可能会出现找不到更新过的实体类这种情况;