1、 简介

  ORM框架:Object Relation Mapping,用操作对象的方式来操作数据库

  其它框架:Dapper、NHibernate,首推EF,微软官方的。

  EF底层还是ADO.NET实现的。

  EF支持SqlServer、MySQL、Oracle等主流数据库

  使用EF开发数据库有两种形式:先建数据库or先建模型类

  三种模式:DataBase First数据库优先;先建数据库表结构,生成EDM文件

  Model First模型优先;没啥用

  Code First:代码优先;开发者自己写模型生成数据库,没有EDM文件

  DataBase First:简单、方便,但如果是大项目后期会非常痛苦,会出现诸如:修改了数据库在程序中更新EF不起作用等这类问题。

  Code First:门槛高,但适合大项目,微软主推;数据库由EF帮助生成,当修改模型后,EF使用DB Miguration自动帮助修改数据库,但也可以禁用Miguration,手动创建(推荐)

  EF是采用约定大于配置的框架原则的,能遵守约定的就不要去配置

2、EF的安装

  ①程序中右键新建项

  ②通过NuGet程序集:Install-Package EntityFramework

  会自动在App.config中增加两个entityFramework配置段,如果是MySql数据库还需要添加相关的MySql的驱动。

  在Web.config中配置连接字符串

  1. <connectionStrings>
  2.  
  3. <add name="connStr" connectionString="Data source=.;initial catalog=School;user id=sa;password=***;" providerName="System.Data.SqlClient" />
  4.  
  5. </connectionStrings>

3、EF简单实体配置DataAnnotations

  数据库建表T_Persons

  程序中实体类Person类

  1. [Table("T_Persons")]//表名与类名不一样,所以需要特性标注
  2.  
  3. public class Person{
  4.  
  5. public long Id { get; set; }
  6.  
  7. public string Name { get; set; }
  8.  
  9. public DateTime CreateDateTime { get; set; }
  10.  
  11. }

  备注:因为EF约定主键字段时Id,所以不用再特殊指定Id是主键;主键必须是Id,可以配置但不推荐

  常用特性:必填字段[Required]、限制字段长度[MaxLength(5)]、字段在数据库中有默认值[DatabaseGenerated]、可空字段int?用问号修饰、字段需要用public

  1. //创建实体类
  2.  
  3. public class TestDbContext:DbContext{
  4.  
  5. public TestDbContext()
  6.  
  7. : base("name=connStr")
  8.  
  9. {
  10.  
  11. }
  12.  
  13. //通过对Persons操作就可以完成对T_Persons表的操作
  14.  
  15. public DbSet<Person> Persons { get; set; }
  16.  
  17. }

  是否using的争议

  不using也没问题,但其实using更好。推荐using

  异常处理:

  InnerException

4、EF模型的两种配置方式

①DataAnnotaions;方便,偶尔度高,上边那种

②FluentAPI;微软推荐使用的

5、FluentAPI使用

①sql中建表

②C#建模型类

③创建PersonConfig类

  1. using System.Data.Entity.ModelConfiguration;
  2.  
  3. public class PersonConfig:EntityTypeConfiguration<Person>{
  4.  
  5. public PersonConfig() {
  6.  
  7. this.ToTable("T_Persons");
  8.  
  9. }
  10.  
  11. }

④创建DbContext类

  1. public class MyContext:DbContext{
  2.  
  3. public MyContext() : base("name=connStr") {
  4.  
  5. }
  6.  
  7. public DbSet<Person> Persons { get; set; }
  8.  
  9. protected override void OnModelCreating(DbModelBuilder modelBuilder){
  10.  
  11. base.OnModelCreating(modelBuilder);
  12.  
  13. //当前代码所在程序集,加载所有的继承自EntityTypeConfiguration为模型配置类 modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly());
  14.  
  15. }
  16.  
  17. }

当存在多表时,只要添加多个实体类与DbSet就可以了

6.、EF的原理及sql监控

EF会自动把where、OrderBy、Select等这些编译成“表达式树(Expression Tree)”,然后会把表达式树翻译成SQL语句执行。因此不是把数据都取到内存中,然后使用集合的方式进行数据过滤,因此性能不会低。但如果这个操作不能被翻译成sql语句,则会报错,或者被放在内存中操作,性能就会很低。

查看真正执行的sql是什么样的

  1. MyContext ctx = new MyContext();
  2.  
  3. ctx.Database.Log = (sql) =>{
  4.  
  5. Console.WriteLine("=============Log============" + sql);
  6.  
  7. };

EF的延迟执行

  只有遍历结果集的时候才执行select查询,ToList()内部也是遍历结果集行成List

各种语句编译后的结果

  1. Person p=ctx.Persons.First();
  2.  
  3. p.Name = "hello word";
  4.  
  5. ctx.SaveChanges();

Log

EF很智能,知道我只是更新Name字段,而且主动的帮我找到ID;

值得一提的是如果你重复执行语句,那么EF也很聪明的不会执行该update语句...

ctx.Persons.Where(o => o.Name.StartsWith("baidu")).ToList();

var result = ctx.Persons.Where(p => p.Name.Contains("com"));

则是%com%

var result = ctx.Persons.Where(p => p.Name.Length > 5).ToList();

该语句生成的sql相对复杂些,而且字段上涉及到了数据类型转换(将得到的字段值转换成int类型再比较),它的执行效率就比较低。

var result = ctx.Persons.Where(p => p.CreateDateTime > DateTime.Now).ToList();

long[] ids = { 2, 5, 6 };

var result = ctx.Persons.Where(p => ids.Contains(p.Id)).ToList();

EF很强大,自动帮助拼接了字符串

IEnumerable<Person> p = ctx.Persons.Where(o => o.Id > 3);

p=p.Where(o => o.Name.Length > 3);

p.ToList();

第一次获得IEnumerable<Person> p时,已经把数据加载入内存了,又在内存中操作效率就很低。

IQueryable<Person> p = ctx.Persons.Where(o => o.Id > 3);

p=p.Where(o => o.Name.Length > 3);

p.ToList();

使用IQueryable<Person> 对象时,所有的操作都是在数据库中执行的,最后返回给程序

如果使用IEnumerable<Person>时,是把所有id>3的都加载到内存中又Linq to Object查询了一次这样非常不好。

EF 是跨数据库的,如果迁移到 MYSQL 上, 就会翻译成 MYSQL 的语法。要配置对应
数据库的 Entity Framework Provider

细节:
每次开始执行的__MigrationHistory 等这些 SQL 语句是什么?

是 DBMigration 用的,也就是由 EF 帮我们建数据库,现在用不到,

通过下面的代码禁用:
Database.SetInitializer<XXXDbContext>(null);
XXXDbContext 就是项目 DbContext 的类名。一般建议放到 XXXDbContext 构造函数中
注意这里的 Database 是 System.Data.Entity 下的类,不是 DbContext 的 Database 属性。如果写到 DbContext 中,最好用上全名,防止出错。

7、EF执行sql

在一些特殊场合,需要执行原生 SQL。比如Sqlserver有一些特有的函数,EF就无法使用语句生成,因为EF是垮数据库的,不能支持所有的特性。
执行非查询语句,调用 DbContext 的 Database 属性的 ExecuteSqlCommand 方法,可以
通过占位符的方式传递参数:

  1. ctx.Database.ExecuteSqlCommand("update T_Persons set Name={0},CreateDateTime=GetDate()",
  2. "baidu.com");

占位符的方式不是字符串拼接,经过观察生成的 SQL 语句,发现仍然是参数化查询,因此不会有 SQL 注入漏洞。
执行查询:

  1. var q1 = ctx.Database.SqlQuery<Item1>("select Name,Count(*) Count from T_Persons where Id>{0} and
  2. CreateDateTime<={} group by Name",2, DateTime.Now); //返回值是 DbRawSqlQuery<T> 类型,也是实现了 IEnumerable 接口

类似于 ExecuteScalar 的操作比较麻烦:
int c = ctx.Database.SqlQuery<int>("select count(*) from T_Persons").SingleOrDefault();

8、EF中不是所有lambda写法都能被支持

var result = ctx.Persons.Where(p => Convert.ToString(p.Id)=="3");

出现“System.NotSupportedException”异常一般就说明你的写法无法翻译成 SQL 语句。

想获取创建日期早于当前时间一小时以上的数据:
var result = ctx.Persons.Where(p => (DateTime.Now - p.CreateDateTime).TotalHours>1);
同样也可能会报System.ArgumentException 类型的未经处理的异常

也就是说EF使用lambda表达式中不能发生,计算or类型转换操作

EF中提供了一个SqlServer专用的类,SqlFunctions,这个方法只对Sqlserver数据库支持,对于在EF不支持的函数提供支持;

比如:var result = ctx.Persons.Where(p =>

SqlFunctions.DateDiff("hour",p.CreateDateTime,DateTime.Now)>1);

9、EF对象状态管理

为什么查询出来的对象 Remove()、再 SaveChanges()就会把数据删除。 而自己 new 一个Person()对象,然后 Remove()不行?
为什么查询出来的对象修改属性值后、再 SaveChanges()就会把数据库中的数据修改。
因为 EF 会跟踪对象状态的改变。
EF 中对象有五个状态:

Detached(游离态,脱离态) 、

Unchanged(未改变) 、Added(新增) 、Deleted(删除) 、 Modified(被修改)

状态的装换

Add()、 Remove()修改对象的状态。 所有状态之间几乎都可以通过: Entry(p).State=xxx 的方式进行强制状态转换。状态改变都是依赖于 Id 的( Added 除外)

应用
  当 SavaChanged()方法执行期间,会查看当前对象的 EntityState 的值,决定是去新增
( Added)、修改( Modified)、删除( Deleted)或者什么也不做( UnChanged)。

10、EF优化的一个技巧

如果查询出来的对象只是供显示使用,不会修改、删除后保存,那么可以使用
AsNoTracking()来使得查询出来的对象是 Detached 状态,这样对对象的修改也还是 Detached状态, EF 不再跟踪这个对象状态的改变,能够提升性能。

  1. var p1 = ctx.Persons.Where(p => p.Name == "baidu.com").FirstOrDefault();
  2. Console.WriteLine(ctx.Entry(p1).State);
  3. //改成:
  4. var p1 = ctx.Persons.AsNoTracking().Where(p => p.Name == "baidu.com").FirstOrDefault();
  5. Console.WriteLine(ctx.Entry(p1).State);
  6. 因为 AsNoTracking()是 DbQuery 类( DbSet 的父类)的方法,所以要先在 DbSet 后调用
  7. AsNoTracking()

如果确实还想再更新,ctx.Entry().State=System.Data.Entity.EntityState.Unchanged;后在更新即可。

EntityFramework使用及优化的更多相关文章

  1. 你真的了解EF吗?关于EntityFramework的高级优化

    接上一篇文章.现在写程序,做项目不是说功能做完就完事了,在平常的开发过程中对于性能的考虑也是极其重要的. 关于ef的那些事,今天就来说说吧.首先必须得知道.net ef在程序中的五种状态变化过程与原理 ...

  2. EntityFramework Code First 优化-IIS 8的第一次优化请求配置

    首先需要在Window中添加Application Initialization Application Initialization 在IIS中配置Application Pool 编辑Applic ...

  3. EntityFramework Core不得不注意的性能优化意外收获,你会用错?

    前言 这两天在着实研究EF Core项目当中对于一些查询也没实际去检测,于是想着利用放假时间去实际测试下,结果本文就出来了,too young,too simple,后续博主会从底层翻译表达式树弄起, ...

  4. 【开源】OSharp框架解说系列(1):总体设计及系列导航

    系列文章导航 [开源]OSharp框架解说系列(1):总体设计 [开源]OSharp框架解说系列(2.1):EasyUI的后台界面搭建及极致重构 [开源]OSharp框架解说系列(2.2):EasyU ...

  5. Entity Framework 6 Code First +MVC5+MySql/Oracle使用过程中的几个问题

    1. namespace Snapsia.Web.Models { using System; using System.Data.Entity; using System.ComponentMode ...

  6. OSharp框架总体设计

    OSharp框架解说系列(1):总体设计 〇.前言 哈,距离前一个系列<MVC实用构架设计>的烂尾篇(2013年9月1日)已经跨了两个年头了,今天是2015年1月9日,日期已经相映,让我们 ...

  7. EntityFramework 优化建议

    Entity Framework目前最新版本是6.1.3,当然Entity Framework 7 目前还是预览版,并不能投入正式生产环境,估计正式版16年第一季度会出来,了解过EF7的部分新特性后, ...

  8. EntityFramework之异步、事务及性能优化(九)

    前言 本文开始前我将循序渐进先了解下实现EF中的异步,并将重点主要是放在EF中的事务以及性能优化上,希望通过此文能够帮助到你. 异步 既然是异步我们就得知道我们知道在什么情况下需要使用异步编程,当等待 ...

  9. EntityFramework优化:第一次启动优化

    1. 预先生成视图 通过代码的方式来预先生成视图,要求EntityFramework是6.0及以上版本. 控制台程序: using System.Data.Entity.Infrastructure; ...

随机推荐

  1. MongoDB 博客截图之二

    使用内置帮助help() 基本命令示例 来源:MongoDB基本管理命令 - 千与的专栏 - 博客频道 - CSDN.NET

  2. PowerDesigner 逆向工程 Could not Initialize JavaVM!

    原项目的大量的表,使用PowerDesigner 进行逆向工程.提示Could not Initialize JavaVM! 网上找到原因,PowerDesigner 不可以使用64位JDK环境! 有 ...

  3. java线程入门知识

    为什么需要多线程? . 模型的简化,如某些程序是由多个相对独立任务的运行: . 图形界面的出现,输入.输出的阻塞 . 多核CPU的更好利用 . 异步行为的需要 Java多线程的特性: . 程序的入口m ...

  4. Qt5.2 for Android 配置及部署到手机运行

    使用DNK编程也没有那么难,使用QT为安卓跨平台编程需要安装NDK,SDK通过NDK调用C++程序,偶尔能提高一些效率. SDK下载地址:http://developer.android.com/sd ...

  5. BZOJ 3940: [Usaco2015 Feb]Censoring AC自动机_栈

    Description Farmer John has purchased a subscription to Good Hooveskeeping magazine for his cows, so ...

  6. C语言基础 (5) 常用操作符

    01 课程回顾 变量的起名:字母数字下划线 不能是关键字 常量 变量提升:老的编译器这样会报错 运算符:sizeof.+.-.x … … 进制: 1111 8421 计算机几乎都是二进制系统,而且是以 ...

  7. Asp 6种页面转向方法

    asp.net 页面转向方法其实就是两种 服务器端转向和客户端转向 客户端转向实质上是指由浏览器直接向服务器端重新发送一个请求. 而服务器端转向是指服务器内部进行页面的跳转. 服务器端转向和客户端转向 ...

  8. 修改默认input(file)的样式

    以上是默认的 <input type="file" > 但是丑爆了啊同志们~~长久以来都是调用大神的代码,今天我也小试牛刀,做出了如下效果: 这样还是能接受的样子啦~ ...

  9. [luogu3237 HNOI2014] 米特运输 (树形dp)

    传送门 Description 米特是D星球上一种非常神秘的物质,蕴含着巨大的能量.在以米特为主要能源的D星上,这种米特能源的运输和储存一直是一个大问题. D星上有N个城市,我们将其顺序编号为1到N, ...

  10. Python半双工聊天

    半双工聊天 半双工聊天.创建一个简单的半双工聊天程序.指定半双工,我们的意思就是,当建立一个连接且服务开始后,只有一个人能打字,而另一个参与者在得到输入消息提示之前必须等待消息.并且,一旦发送者发送了 ...