ADO.NET Entity Framework 在哪些场景下使用?
在知乎回答了下,顺手转回来。
Enity Framework已经是.NET下最主要的ORM了。而ORM从一个Mapping的概念开始,到现在已经得到了一定的升华,特别是EF等对ORM框架面向对象能力的升华。切实地说,就是ORM让数据库在整个应用过程中更好地被封装和抽象化。
ORM一开始只是Mapping,最基础的就是表与类的对应、Column和属性的对应,这只是最基础的。在这个层次上,数据库对象通过Mapping在面向对象语言层面,也就是业务层面被封装成了业务对象,然后允许以操作业务对象的方式对数据库进行操作。
但是,在很长时间里,ORM的提升都被对象与关系间的“阻抗失配”困扰。一直以来很多ORM的水平都只是维持在了用对象的方式进行CRUD而已,除了减少代码错误、提高简单查询的开发效率,在复杂查询、性能等等一些方面结果都还是要跨层回到底层的操作框架比如ADO.NET甚至存储过程去解决问题。
所以,在应用场景上来说简单查询的场景EF和其他ORM都是能够胜任的。
从应用场景说起,这点在B/S和C/S里也会很明显。用户使用Web的时候和使用桌面软件的最大体验不同是什么?——所见即所得。你在网页上操作了半天,一个关闭就全没了,还必须提交然后获得下一个页面才能把数据状态和UI更新;而同样在桌面上,你的操作比如画图,在操作的一瞬间结果就出来了。当然了,Web 2.0技术就在解决这个问题。
同样在OO和RDBMS中的问题也在这里。
从OO的角度上看,你运行下一段代码结果如何:
user.Name = "Indream Luo";
在OO里,就是user对象的Name属性被更新了。如果是一个桌面软件,那么用户的名称应该也更改了。
但是如果这个对象的数据是存在关系数据库中,或者任意数据库,那么结果都逃脱不出这个套路:
var object = db.Get(id);
change(ref object);
db.Update();
你需要把更新Push过去,将操作和数据持久化。
在存储分层开始,推送更新就不可避免,哪怕在说面应用中,也是将对象的更新推送到了UI。ORM站立在应用场景不一致中间所要扮演的角色,就是一个润滑剂的角色。
在我所能马上想起的特性,就是EF和NHibernate的缓存机制。EF是一级缓存,NH是二级缓存,手动的话似乎EF也可以做到二级。然后在.NET下最重要的一点是有LINQ。LINQ在有合适的Provider的情形下可以把OO的序列化操作转化成目标的序列化操作,在这里就是LINQ转SQL,这样就省去了拼接SQL、SQL注入等很多麻烦。另外LINQ延迟加载的特性也很大地减少了用户控制SQL执行的工作。
在操作同步的基础上,还有结构同步的问题。表结构和对象结构同步是使用ORM一大工作内容。EF有默认的生成工具,DB First、Model First、Code First三种模式提供选择,加上自动生成同步SQL,选择性是现在最广的,NH也有一些相应的生成器,数据库优先方面小弟LINQ to SQL的拖拽最惊艳。
在这个场景下,加上对相关工具的利用,EF等ORM适用于序列操作、减少数据库操作管理和结构同步工作量,减少开发成本。
最后,不可回避的就是阻抗失配的问题。
对象关系模型和关系数据库模型在以前很大程度上不一致,这是在以前。现在ORM要做的就是如何让两者更接近,让一边的特性能更顺滑地体现在另一边。
我 在早几个月写过一篇总结,关于最近一个项目EF使用的一些方法——《Entity Framework 与 面向对象》。太长就选重点来说明。
EF所做的涵盖:类型匹配、对象结构、数据源区分。
类型匹配方面,就是把OO类型和数据库类型进行匹配,这是ORM的基础。基础类型中的整数、浮点、字符串、日期这些不在话下,EF比较有特点的可能是枚举类型(Enum)、复杂类型(Complex Type)、地理位置的功能,实现方式也比较理想。
对象结构方面是EF让我最惊艳的地方。EF的Model,也就是Entity能实现集成关系,也可以通过此同步在表结构中;EF中通过对外键的控制,对引用和依赖关系实现得十分出色;支持虚类、对象层面的Get/Set、访问控制都很好用。
插一段,通过使用Model First,我倒是发现数据库的设计更加接近于范式了。因为LINQ和对象结构方面带来的便利,我可以把表结构设计得更“合理”。比如如果要获取user的上司的上司,假设每个User都只有一个上司,那么用EF或者一些ORM就是:
var bigBoss = user.Superior.Superior;
如果要写SQL,感觉有点烦,算代码量和可读性已经能看出区别了。
最后是数据源区分。有一个问题是一个对象,它的数据不一定完全源于数据库,或者一个数据库,这个例子我常用。
比如User有三个字段:FirstName、LastName、FullName。可以知道FullName其实就是FirstName和LastName的拼接,如果创建Model/Entity,一般:
public partial class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName
{
get
{
if (fullName == null)
{
this.fullName = String.Format("{0} {1}", this.FirstName, this.LastName);
}
return this.fullName;
}
} string fullName;
}
而在数据库里,只需要存储FirstName和LastName,FullName作为计算值就可以了,而且还是延迟加载的。
更甚者,我们还可以从上面的例子延伸,在Entity中封装一些数据库操作:
public partial class User
{
public User Superior { get; set; }
public User BigBoss
{
get
{
return this.Superior.Superior;
}
}
}
此时在数据库中只存储一个Superior关系即可,BigBoss作为计算值就可以了。当然,你乐意还可以缓存和延迟加载,但EF已经处理了缓存了。
极端情况,确实是可以在表关系中“玩”不少面向对象的设计模式。
终上所述,EF适用于面向对象结构和特性优先性比较高的 场景。
那么相对地,也说说不适用的场景。
首先大家所诟病的是性能问题,这点希望不要抛开原理去说EF的性能。
EF由于其执行原理,性能损耗一般发生在:
- LINQ也就是Expression Tree创建和转换成SQL的过程
- 缓存比对的过程
- 特殊操作实现不合理
- 极限性能压力下的问题
- 性能泄露
1是不可避免的,2通过关闭比对或者缓存可以解决,3、4和5是主要问题。
特殊操作不合理举例来说,比如递归,获取一个树结构的一条索引链。如果是通过OO来做,那么就是要么要往返很多次数据库,要么要至少遍历一次对象表,要么就是要加一些特殊的“丑陋的”索引字段。
极限性能压力在包含上个问题的情况下扩展,比如SQL Server的存储过程执行的特殊操作是最快的,纯OO的方式肯定达不到。
这两项特殊项通过更原生的数据库方式去解决是最佳的解决方案。你可以和EF混用,也可以单独使用,但不要妄想着有银弹能同时解决所有问题。EF提供了SQL的执行方式。
性能泄露不是一个专有名词,是我临时用的。意思是因为EF导致的不必要的性能浪费。特别是LINQ的延迟加载特性,许多不清楚LINQ特性的开发人员容易将LINQ序列无谓地实例化,浪费了系统资源。通常会是:
- 遍历查询全表数据, 然后再在OO层面进行筛选
- 无谓地执行实例化,进行查询,要么浪费缓存比对的资源,要么浪费查询资源
我只能说这是开发人员水平问题,虽然出现问题后很难定位,特别是一般情况下都会造成内存泄露。
最后最常见的还是回到数据模型同步的问题。当数据模型更改后,需要同步,这时候如果已经有业务数据了,是一件麻烦的事情。EF的Migration我没用过,是一个解决方案但似乎不那么完美。在一些非ORM应用的系统,SQL集中管理架构下,在这个场景,可能会更容易进行维护。
ADO.NET Entity Framework 在哪些场景下使用?的更多相关文章
- ADO.NET Entity Framework
ADO.NET Entity Framework 是微软以 ADO.NET 为基础所发展出来的对象关系对应 (O/R Mapping) 解决方案, 早期被称为 ObjectSpace,现已经包含在 V ...
- ADO.NET Entity Framework学习笔记(3)ObjectContext
ADO.NET Entity Framework学习笔记(3)ObjectContext对象[转] 说明 ObjectContext提供了管理数据的功能 Context操作数据 AddObject ...
- 让ADO.NET Entity Framework 支持ACCESS数据库
如写的不好请见谅,本人水平有限. 个人简历及水平:. http://www.cnblogs.com/hackdragon/p/3662599.html 接到一个程序和网页交互的项目,用ADO.NET ...
- ADO.NET Entity Framework Extensions
一.情景 如果你的项目中有返回多结果集的存储过程. 如果你的项目要和老项目中的ADO.Net共用事务. 如果你要动态的创建数据库的表. 但是你还是希望使用Entity Framework.那么继续往下 ...
- APS.NET MVC + EF (02)---ADO.NET Entity FrameWork
2.1 Entity Framework简介 Ado.net Entity Framework 是Microsoft推出的ORM框架. 2.1.1 什么是ORM 对象关系映射(Object Relat ...
- ADO.NET-EF:ADO.NET Entity Framework 百科
ylbtech-ADO.NET-EF:ADO.NET Entity Framework 百科 ADO.NET Entity Framework 是微软以 ADO.NET 为基础所发展出来的对象关系对应 ...
- ADO.NET Entity Framework CodeFirst 如何输出日志(EF 5.0)
ADO.NET Entity Framework CodeFirst 如何输出日志(EF4.3) 用的EFProviderWrappers ,这个组件好久没有更新了,对于SQL执行日志的解决方案的需求 ...
- 如何得到EF(ADO.NET Entity Framework)查询生成的SQL? ToTraceString Database.Log
ADO.NET Entity Framework ToTraceString //输出单条查询 DbContext.Database.Log //这里有详细的日志
- Microsoft SQL Server Compact 4.0&&ADO.NET Entity Framework 4.1&&MVC3
最近重新查看微软MvcMusicStore-v3.0的源代码,发现忽略了很多重要的东西,特别是数据访问那一部分. 首先Microsoft SQL Server Compact 4.0 详细的介绍和下载 ...
随机推荐
- 构建一个基本的前端自动化开发环境 —— 基于 Gulp 的前端集成解决方案(四)
通过前面几节的准备工作,对于 npm / node / gulp 应该已经有了基本的认识,本节主要介绍如何构建一个基本的前端自动化开发环境. 下面将逐步构建一个可以自动编译 sass 文件.压缩 ja ...
- Storm如何保证可靠的消息处理
作者:Jack47 PS:如果喜欢我写的文章,欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源. 本文主要翻译自Storm官方文档Guaranteeing messag ...
- 简单入门canvas - 通过刮奖效果来学习
一 .前言 一直在做PC端的前端开发,从互联网到行业软件.最近发现移动端已经成为前端必备技能了,真是不能停止学习.HTML5新增的一些东西,canvas是用的比较多也比较复杂的一个,简单的入门了一下, ...
- 如何在高并发环境下设计出无锁的数据库操作(Java版本)
一个在线2k的游戏,每秒钟并发都吓死人.传统的hibernate直接插库基本上是不可行的.我就一步步推导出一个无锁的数据库操作. 1. 并发中如何无锁. 一个很简单的思路,把并发转化成为单线程.Jav ...
- Unity 序列化
Script Serialization http://docs.unity3d.com/Manual/script-Serialization.html 自定义序列化及例子: http://docs ...
- PHP与JAVA构造函数的区别
早期的PHP是没有面向对象功能的,但是随着PHP发展,从PHP4开始,也加入了面向对象.PHP的面向对象语法是从JAVA演化而来,很多地方类似,但是又发展出自己的特色.以构造函数来说,PHP4中与类同 ...
- css3圆形百分比进度条的实现原理
原文地址:css3圆形百分比进度条的实现原理 今天早上起来在查看jquery插件机制的时候,一不小心点进了css3圆形百分比进度条的相关文章,于是一发不可收拾,开始折腾了... 关于圆形圈的实现,想必 ...
- 微信小程序前端源码逻辑和工作流
看完微信小程序的前端代码真的让我热血沸腾啊,代码逻辑和设计一目了然,没有多余的东西,真的是大道至简. 废话不多说,直接分析前端代码.个人观点,难免有疏漏,仅供参考. 文件基本结构: 先看入口app.j ...
- 微信小程序教程汇总
目前市面上在内测期间出来的一些实战类教程还是很不错的,主要还是去快速学习小程序开发的整体流程,一个组件一个组件的讲的很可能微信小程序一升级,这个组件就变了,事实本就如此,谁让现在是内测呢.我们不怕,下 ...
- 原生JavaScript实现hasClass、addClass、removeClass、toggleClass
兼容IE6+,因IE6.IE7.IE8不支持Array.prototype.indexOf()和String.prototype.trim(),分别用Polyfill实现支持. 详细: indexOf ...