前言:
在三层架构中通过ADO.net框架操作数据库,感觉入手还算简单,操作起来也比较简单,通俗易懂。但是目前出现了【Ado.net】 EF-最强大的ORM。
何为ORM:对象关系映射:通俗说,用操作对象的方式来操作数据库;
何为EF:基于ORM思想的一种新型的操作工具;其它还有Dapper、PetaPoco等;EF底层仍旧是对Ado.net的封装,EF支持目前主流的数据库;
准备工作:
(1)建数据库、建模型类:
(2)创建EF三种方式:
Database First(数据库优先):先创建数据库,然后自动生成EDM文件,EDM文件生成模型类。
更改数据库表结构后,导致人为更新数据库表,
如果遇到多人同时操作同一个表,会出现很大的问题
特殊情况下,还会出现无法更改相应的表结构
Model First(模型优先):先创建EDM文件,Edm文件自动生成模型类和数据库。
Code First(代码优先):自己手写模型类,自动生成数据库,没有Edm。
疑问?
了解了这么多,那么我们为什么要使用EF那,怎么感觉使用EF后突然变得更麻烦了;能够这样想,说明我们思考了这个问题,就是变得麻烦了;
但是,EF却在Ado.net直接和数据库打交道,直接操作数据库的基础上进行了封装,对数据表进行了映射处理,以对象的形式展现在面前,充分的体现了“面向对象”的思想。
开发人员通过Lamba语句(一般SQL语句)和Linq语句(复杂SQL语句)实现增删改查,编译错误后不通过,当然最终还是需要转换为sql语句来执行。
如果说到这里,想必大家了解了EF的劣势了,性能比较与Ado.net稍差,如果操作大量的数据,推荐使用原生的Ado.net;
优势:
(1)跨数据库操作,修改配置文件即可;
(2)与VS结合性(微软推荐)好;
(3)开发效率高,根据面向对象的思维进行软件的开发;
(4)EF同样推荐在EF语法中使用原生的ado.net进行数据库操作,省去了防止sql注入的麻烦;
ctx.Database.ExecuteSqlCommand("update T_Persons set Name={0},CreateDateTime=GetDate()", "25");
配置方式(EF模型):
DataAnnotations、FluentAPI:第一种耦合度偏高,一般的类最好是POCO(原生老的对象),后者最为合适;
(1):通过配置文件,做到模型反射到相应的数据库;
public class PersonConfig: EntityTypeConfiguration<Person>
{
public PersonConfig()
{
this.ToTable("T_Persons");//等价于[Table("T_Persons")]
}
}
创建类:连接数据库+重写(DbContent)方法,应用反射,使配置文件发挥作用;
public class MyDbContext:DbContext
{
public MyDbContext():base("name=conn1")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly());
//代表从这句话所在的程序集加载所有的继承自EntityTypeConfiguration为模型配置类。
}
public DbSet<Person> Persons { get; set; }
}
(2):不同于反射自己手动加载配置文件;
(3):省略配置文件,然后直接把数据库中的映射,放到类中;
原理:
EF会自动把Where()、OrderBy()、Select()等这些编译成“表达式树(Expression Tree)”,然后会把表达式树翻译成SQL语句去执行。而不是“把数据都取到内存中,然后使用集合的方法进行数据过滤”,因此性能不会低”;
但是如果这个操作不能被翻译成SQL语句,则或者报错,或者被放到内存中操作,性能就会非常低。通过EF实现基本的增删改查,EF中的查询是“延迟执行”的,只有遍历结果集的时候才会执行select查询
扩充:
(1)EF约定主键字段名是Id,所以不用再特殊指定Id是主键,如果非要指定就指定[Key]。
(2)在Ado.net中几乎都可以使用数据库的相应函数,但是在EF中却很多都不可以使用,此时EF中提供了sqlserver数据库中专用的类SqlFunctions,对于EF不支持的函数提供了支持;
var result = ctx.Persons.Where(p =>SqlFunctions.DateDiff("hour",p.CreateDateTime,DateTime.Now)>1);
(3)EF的动态复合检索,这样的操作返回值必须是“IQueryable”,不能使用“IEnumerable”,后者会在内存中读取后续数据;
EF对象的状态:
为什么我们可以通过EF的简单操作,便可以把数据库中的数据修改?此时我们可以追踪对象状态!!!
五个状态:Detached(游离态)、Unchanged(未改变)、Added(新增)、Deleted(删除)、Modified(被修改)
相应的状态转换可以参考:
EF优化技巧:
如果查询出来的独享只是供显示,而非修改、删除后保存的话,可使用AsNoTracking()来使得查询出来的对象是Detached状态,这样对数据的修改和删除同样无效;EF不会再跟踪这个对象状态的改变,能够提升性能。
var p1 = ctx.Persons.AsNoTracking().Where(p => p.Name == "hgoa").FirstOrDefault();
后续:
刚刚说了这么多,怎么还需要人为手动的建立数据库,那么我是不是白学了EF了,哈哈,当然不是了,我们漏掉了EF中自动生成数据库的配置方法FLuentAPI;
基本配置:EF只需配置实体类和表、字段之间的对应关系,表间关联关系即可。
高级配置:可以达到更多效果;如果数据错误(比如字段不能为空、字符串超长等),会在EF层就会报错,而不会被提交给数据库服务器再报错;如果使用自动生成数据库,也能帮助EF生成更完美的数据库表。
-----------------------------------------------后续内容继续推送,敬请期待吆!!!--------------------------------------------------