1. ORM框架之EntityFramework介绍

目录

1. 自我介绍

传说中的程序猿

大家好!我是高堂。
作为一位伪前端程序猿,我给大家介绍一下微软的自家的 ORM框架

ADO.NET Entity Framework 以下简称 EF

2. 什么是EF?

ADO.NET Entity Framework

微软用来替代ADO.NET的一套 ORM 框架.

以 Entity Data Model (EDM) 为主,将数据逻辑层切分为三块,分别为 Conceptual Schema, Mapping Schema 与 Storage Schema 三层,其上还有 Entity Client,Object Context 以及 LINQ 可以使用。

EF框架 发展历史:

版本 支持.NET 发布情况 备注
EntityFramework 3.5 2.0+ 包含于.NET 3.5中 支持EDMX生成,通过扩展可支持POCO类的生成
Entity Framework 4.0 4.0+ 包含于.NET 4.0中
Entity Framework 4.X 可通过NuGet获取 支持Database First、Model First、Code First三种生成模式
Entity Framework 4.5 4.5+ 集成于.NET 4.5中
Entity Framework 5.X 4.5+ 可通过NuGet获取 支持枚举字段,性能有较大提升,支持.NET 4.0的版本 为Entity Framework 4.4
EnittyFramework 6.X 4.0+ 可通过NuGet获取
EnittyFramework 7.X 4.6+ 可通过NuGet获取 现在更名为 EntityFramework Core,结合Net Core使用,多用于跨平台

ADO.NET: 一般使用SQLHelper直接来操作数据库。

3. 什么是 ORM ?

O/R Mapping 关系图

ORM => 对象关系映射(英语:Object Relational Mapping)对于O/R,即 Object(对象)和 Relational(关系型数据),表示必须同时使用面向对象和关系型数据进行开发。

ORM框架 用途 => 为了解决 软件项目数据库 打交道的中间层。

为什么需要 ORM框架 呢?

因为软件项目 是面向对象为基本原则; 而 数据库 则是从数据理论发展而来的;两套理论存在明显的的差异。

ORM框架 到底是什么呢? 我还是不太清楚!!!
ORM 其实有三大核心原则:

  • 简单:以最基本的形式建模数据。
  • 传达性:数据库结构被任何人都能理解的语义化文档。
  • 精准性:基于数据模型创建正确标准了的结构。

简单的说 ORM 相关于中继数据。具体到产品上,例如 ADO.NET Entity Framework 实体类的属性,就算是一种中继数据。在后面我会给大家详细介绍 EF框架

4. EF 与 ADO.NET 有关系吗?

EF首先生成sql,再调用ado.net访问数据库,最后使结果对象具体化.

5. EF 与 ADO.NET 的对比——EF优势何在?

  • 业务逻辑数据存取逻辑分离开来;
  • 新增操作 EF:一次连接,执行多条sql;SqlHelper里使用一般写法,连接又无法释放,用using,会造成多次连接重置;
  • 更新操作 EF自动优化,只update set 有变化的字段,EF也可以很方便地只更新实体的指定属性,产生的sql语句里的set后的字段会更少;
  • 智能提示 用linq, lamda表达式 有智能提示,写错了编译不过;写sql语句字符串,调sqlhelper,sql语句写错一样编译通过;
  • 安全 省去了防止sql注入的麻烦;
  • 数据库变更 使用EF,切换较方便;
  • 效率 使用EF要比使用Ado.net开发效率高;
  • 可读性 代码的可读性更高.

6. 世面上有哪一些 ORM 产品呢?

  • NHibernate框架 来源于 Java 的 Hibernate 框架,采用XML文件配置的方式。
  • Castle ActiveRecord 框架 是 Castle 中的一个子项目,底层封装了 NHibernate,改用 Attribute 来代替配置文件,这样就不用像 NHibernate 那样配置复杂的文件了。
  • iBATIS.NET 框架 分为 DataMapper 和DataAccess两部分,DataMapper是这个框架的核心, DataMapper使用XML文件实现从实体到 SQL statements 的映射,学习起来非常简单,使用DataMapper 以后,我们可以自由的使用 SQL 语句或存储过程; DataMapper 允许我们通过一个简单的接口来操作数据,而不必了解底层实现的细节。
  • ADO.NET Entity Framework框架 是NET开发人员的福音,微软的东西,简单,容易上手等特点。和 Visual Studio SQLServer等软件无缝集成,作为一位 NET 阵营的 童鞋们,你们懂的!

7. EF的开发模式

EF的开发模式

从4.1版本开始,EF开始支持三种开发模式

  • Database First模式

我们称之为“数据库优先”,前提是你的应用已经有相应的数据库,你可以使用EF设计工具根据数据库生成数据数据类,你可以使用Visual Studio模型设计器修改这些模型之间对应关系。

  • Model First模式

我们称之为“模型优先”,这里的模型指的是“ADO.NET Entity Framework Data Model”,此时你的应用并没有设计相关数据库,在Visual Studio中我们通过设计对于的数据模型来生成数据库和数据类。

  • Code First模式

我们称之为“代码优先”模式,是从EF4.1开始新建加入的功能。使用Code First模式进行EF开发时开发人员只需要编写对应的数据类(其实就是领域模型的实现过程),然后自动生成数据库。这样设计的好处在于我们可以针对概念模型进行所有数据操作而不必关系数据的存储关系,使我们可以更加自然的采用面向对象的方式进行面向数据的应用程序开发。

8. Entity Framework 增删改查

8.1 增加对象

DbEntity db = new DbEntity();
//创建对象实体,注意,这里需要对所有属性进行赋值(除了自动增长主键外),如果不赋值,则会数据库中会被设置为NULL(注意是否可空)
var user = new User
            {
                Name = "bomo",
                Age = 21,
                Gender = "male"
            };
db.User.Add(user);
db.SaveChanges();

8.2 删除对象,删除只需要对象的主键

DbEntity db = new DbEntity();
//删除只需要主键,这里删除主键为5的行
var user = new User {Id = 5};
//将实体附加到对象管理器中
db.User.Attach(user);
//方法一:
db.User.Remove(user);
//方法二:把当前实体的状态改为删除
//db.Entry(user).State = EntityState.Deleted;
db.SaveChanges();

8.3 修改对象

方法一:

DbEntity db = new DbEntity();
//修改需要对主键赋值,注意:这里需要对所有字段赋值,没有赋值的字段会用NULL更新到数据库
var user = new User
    {
        Id = 5,
        Name = "bomo",
        Age = 21,
        Gender = "male"
    };
//将实体附加到对象管理器中
db.User.Attach(user);
//把当前实体的状态改为Modified
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();

方法二:方法一中每次都需要对所有字段进行修改,效率低,而且麻烦,下面介绍修改部分字段

DbEntity db = new DbEntity();
//修改需要对主键赋值,注意:这里需要对所有字段赋值,没有赋值的字段会用NULL更新到数据库
var user = new User
    {
        Id = 5,
        Name = "bomo",
        Age = 21
    };
//将实体附加到对象管理器中
db.User.Attach(user);

//获取到user的状态实体,可以修改其状态
var setEntry = ((IObjectContextAdapter) db).ObjectContext.ObjectStateManager.GetObjectStateEntry(user);
//只修改实体的Name属性和Age属性
setEntry.SetModifiedProperty("Name");
setEntry.SetModifiedProperty("Age");

db.SaveChanges();

8.4 使用事务:使用事务很简单,只要把需要的操作放在 TransactionScope 中,最后提交.

DbEntity db = new DbEntity();
using (var scope = new TransactionScope())
{
    //执行多个操作
    var user1 = new User
    {
        Name = "bomo",
        Age = 21,
        Gender = "male"
    };
    db.User.Add(user1);
    db.SaveChanges();
    
    var user2 = new User
    {
        Name = "toroto",
        Age = 20,
        Gender = "female"
    };
    db.User.Add(user2);
    db.SaveChanges();

    //提交事务
    scope.Complete();
}

8.5 查询:查询通过LinQ查询.

DbEntity db = new DbEntity(); 
//选择部分字段 
var user = db.User.Where(u => u.Name == "bomo")
                            .Select(u => new {Id = u.Id, Name = u.Name, Age = u.Age})
                            .FirstOrDefault(); 
//只有调用了FirstOrDefault, First, Single, ToList, ToArray等函数才会执行对数据库的查询

9. EF 查询相关

EF提供的查询方式有以下几种

  • 原始SQL查询
  • LINQ To Entity and Lambda
  • ESQL 与 ObjectQuery
  • ObjectQuery 查询生成器

9.1 原始SQL查询

在EF 4.1 新增加的DbContext 除了支持LINQ与Lambda查询外,新增了支持原始SQL查询,但是不支持ESQL与ObjectQuery查询。

DemoDBEntities context = new DemoDBEntities();
DbSet<BlogMaster> set = context.Set<BlogMaster>();
List<BlogMaster> list = set.SqlQuery("select *from BlogMaster where UserId='3'").ToList();
List<BlogMaster> listAll = context.Database.SqlQuery<BlogMaster>("select *from BlogMaster").ToList();

使用原始SQL查询,既灵活又方便维护,加上DbContext泛型处理,可以将最终的查询数据集映射成对象集合。而且SQL语句有错误时,提醒也比较明确。项目中,大家都会碰到查询条件经常变动的问题,针对这种情况我们以使用通过定制的查询模板以SQL拼接的方式解决,而不是修改代码。

9.2 LINQ To Entity and Lambda

这两种是比较常用的方式,也是效率比较高的,简洁方便,但是不灵活,如果条件变了,可能就需要修改代码。相信做过报表的人都曾为复杂的SQL语句以及SQL语句的执行效率头痛过,而LINQ和Lambda 方便就在于可以将复杂的SQL拆分出来,在内存中解决这些数据的合并筛选,并且效率要远高于SQL。我最喜欢的LINQ的一个功能就是他的分组。

DemoDBEntities context = new DemoDBEntities();
DbSet<BlogMaster> set = context.Set<BlogMaster>();
var result = from u in set.ToList()
                        where u.UserID == 3
                        select u;

var resultGroup = from u in set.ToList()
                    group u by u.UserID
                        into g
                        select g;

var list = set.Where(o => o.UserID == 3);
var listGroup = set.GroupBy(o => o.UserID);

不管是哪种方式,LINQ To Entity and Lambda EF 都是支持的。

9.3 ESQL 与 ObjectQuery

首先说明一点,目前DbContext不支持这种方式查询。ESQL同原始SQL 只是写法稍为有点区别,但是特点差不多,灵活易于维护。由于可以拼接ESQL,所以这种方式也可以应对查询条件变化。

DemoDBEntities context = new DemoDBEntities();
//DbSet<BlogMaster> set = context.Set<BlogMaster>();
string queryString = @"SELECT VALUE it FROM DemoDBEntities.BlogMaster as
                    it WHERE it.UserId > @UserId order by it.UserId desc";
ObjectQuery<BlogMaster> query = new ObjectQuery<BlogMaster>(queryString, context);              
// Add parameters to the collection.
query.Parameters.Add(new ObjectParameter("UserId",6));
List<BlogMaster> list = query.ToList();

原始SQL与ESQL 区别在于参数类型的处理,因为原始的SQL你在拼接的条件的时候要对不同的参数值类型处理,例如是where Name='tt' and UserId=6 and Sex=true ,而ESQL则是object传入,直接实现SQL语句的转换。可惜DbContext不支持ESQL,所以只能自己去解决SQL条件不同值类型的拼接处理。

9.4 ObjectQuery 查询生成器

DemoDBEntities context = new DemoDBEntities();
            
ObjectQuery<BlogMaster> query = context.CreateObjectSet<BlogMaster>()
    .Where("it.UserId > @UserId",
    new ObjectParameter("UserId", 6))
    .OrderBy("it.UserId desc");

List<BlogMaster> list = query.ToList();

这种方式基本上有ESQL相同,只是分组,排序,条件过滤都要单独处理,相比就没结合ESQL使用灵活了。

以上四种方式各有优缺点,如果是批量做页面的查询,每个查询页面和条件各不相同,并且查询条件可能会变动的话,建议使用DbContext的SQL查询,或者是ESQL结合ObjectQuery,这两种方式易于通过查询模板拼接生成SQL语句,但不适合生成复杂的SQL语句。

而LINQ or Lambda 以及ObjectQuery方式,则不适合做一些重复查询逻辑的工作,而单独处理一些页面的查询或者复杂的报表还是比较灵活的。

10. 结束语

Thanks everyone!

推荐阅读更多精彩内容

  • 1. 什么是ORM ORM的全称是Object Relational Mapping,即对象关系映射。它的实现思...
    codeice阅读 369评论 0 1
  • 很多应用程序都需要与数据库交互。数据库是一个数据仓库,与文本文件和 XML 文件极其相似。可以想见,使用文件来存储...
    CarlDonitz阅读 81评论 0 1
  • 自从学习.NET以来,优雅的编程风格,极度简单的可扩展性,足够强大开发工具,极小的学习曲线,让我对这个平台产生了浓...
    taony阅读 980评论 0 42
  • “所有不经过导演亲口认同的影评都是过分解读的阅读理解。” —— 沃.兹吉硕德。 在我心里,科幻/魔幻类(以下统称科...
    正在修炼的西瓜君阅读 34评论 0 0
  • 耳匣的你 轻诉胸中那一抹红 浇湿了我的巾帕 打乱了我的盘发 吹响了我的诗句 伪装了你的上卦 左手边 你看过那一场大...
    臾止阅读 28评论 0 1