
ADO.NET Entity Framework 是一个对象-关系的映射架构。它支持直接定义完全独立于数据库结构的实体类,并把它们映射到数据库的表和关系上。
概念
什么是EF?
ADO.NET Entity Framework 是一个对象-关系的映射架构。它支持直接定义完全独立于数据库结构的实体类,并把它们映射到数据库的表和关系上。
三种编程模型:
- 数据库优先开发模式(Database First Development)
- 模型优先开发模式(Model First Development)
- 代码优先开发模式(Code First Development)
EF优点:
- 支持跨数据库,修改配置文件就可以
- 使用linq语句,提高开发效率。但在进行复杂的查询时,EF表现不太好
EF搭建
非常具体的还可以参考官方文档。
来自数据库的EF设计器
创建应用程序
打开VS,随便新建一个项目,MVC、Webform均可。项目创建完成后,右键—项目路径,选择“添加”—“新建项”。点击“数据”—“ADO.NET实体数据模型”—“添加”,名称根据项目或习惯命名即可:

反向工程模型
点击“来自数据库的EF设计器”——“下一步”。点击“新建连接”,连接完成数据库,根据情况选择“是”或“否”,然后依次点击“下一步”。如图:



此时,生成关系图,如下:

在解决方案下可以查看到 .edmx 文件,如图:

读取&写入数据
string name = "露娜";
string newName = "后裔";
using (ExampleInfoContext db = new ExampleInfoContext())
{
//展示数据
var showStudent = from s in db.StudentTable
where s.Sname == name
select s;
foreach (var item in showStudent)
{
ViewBag.NewStudentName += item.Sname + ",";
}
//新增数据
var addStudent = new StudentTable { Sid = 1100, Sname = "肖明", Ssex = "男" };
db.StudentTable.Add(addStudent);
db.SaveChanges();
//修改数据
var student = (from s in db.StudentTable
where s.Sname == name
select s).FirstOrDefault();
student.Sname = newName;
db.Entry(student).State = System.Data.Entity.EntityState.Modified;
if (db.SaveChanges() > 0)
{
ViewBag.ModifyResult = "修改成功!";
}
else
{
ViewBag.ModifyResult = "修改失败!";
}
//删除数据
var removeStudent = db.StudentTable.Where(s => s.Sname == newName).FirstOrDefault();
db.StudentTable.Remove(removeStudent);
db.SaveChanges();
}
处理数据库更改
现在,需要对数据库架构进行一些更改,我们进行这些更改时,我们还需要更新模型以反映这些更改:
- 在 EF 设计器中右键单击模型的空白点,然后选择 “从数据库更新模型 …“,这将启动更新向导。
- 在更新向导的 “添加” 选项卡上,选中 “表” 旁边的框,这表示要从架构中添加任何新表。 @no__t 0The 刷新 “选项卡显示模型中的所有现有表,这些表将在更新过程中检查更改。删除选项卡显示已从架构中删除的所有表,并将作为更新的一部分从模型中删除。这两个选项卡上的信息是自动检测的,并仅供参考,无法更改任何设置。 *
- 在更新向导中单击 “完成”。
操作如图所示:


生成下项目,新增的表就可以显示出来:

Code First到现有数据库
前面步骤和来自数据库的EF设计器的基本一致,只需要在如下位置选择不同的选项

生成文件也不相同,生成了上下文SogalSyncERPContext和多个模型类,如图所示

SogalSyncERPContext派生上下文代码如下:
namespace EFDemo
{
using System;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
public partial class SogalSyncERPContext : DbContext
{
public SogalSyncERPContext()
: base("name=SogalSyncERPContext")
{
}
public virtual DbSet<SyncSplitQueue> SyncSplitQueue { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<SyncSplitQueue>()
.Property(e => e.EmailCode)
.IsUnicode(false);
}
}
}
模型类之一代码如下:
namespace EFDemo
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
[Table("SyncSplitQueue")]
public partial class SyncSplitQueue
{
public int Id { get; set; }
public int OrderId { get; set; }
[StringLength(50)]
public string OrderNo { get; set; }
public int? OrderType { get; set; }
[StringLength(100)]
public string TrackNumber { get; set; }
[StringLength(100)]
public string Approver { get; set; }
public int ProcessCode { get; set; }
public string ErrorMessage { get; set; }
public DateTime CreatedDateTime { get; set; }
public DateTime? ProcessDateTime { get; set; }
public string MRPCheckInfo { get; set; }
[StringLength(50)]
public string EmailCode { get; set; }
public bool? IsCheck { get; set; }
[StringLength(50)]
public string TeamLeader { get; set; }
[StringLength(50)]
public string LockBodyMember { get; set; }
public int SystemType { get; set; }
public int? Times { get; set; }
public string ErrorExclude { get; set; }
public int? ProductOrgId { get; set; }
}
}
查询、修改和删除数据
如上文的读取和写入操作,这里不再赘述。
数据库更改更新模型:
“Code First 到数据库” 向导旨在生成一组可以进行调整和修改的起始点。 如果数据库架构发生更改,则可以手动编辑类,也可以执行其他反向工程来覆盖类。
先定义模型后生成数据库
还有先定义模型,然后生成数据库的操作。他们只需要在创建ADO.NET实体数据模型时候,选择空model,然后根据提示做相应的配置,最后在模型图像界面右击,选择从模型生成数据库就可以了。具体请查看官方文档,这里因为很少进行这样的操作,所以大致介绍下就不再赘述了。
EF深入了解
惰性加载(Lazy Loading)
默认情况下,EF会使用惰性加载方式加载数据,即ctx.Configuration.LazyLoadingEnabled=true;在下面的代码中,外层循环会执行一次查询,并将返回的结果存放在变量q中。而内层循环会在每一次循环过程中独立进行查询,所以,如果数据库表Teacher中有100条记录而Course有1000条记录,那么整个过程将产生1001次查询。
using (var ctx = new SchoolDBEntities())
{
var q = from t in ctx.Teachers
select t;
foreach (var teacher in q)
{
Console.WriteLine("Teacher : {0}", teacher.TeacherName);
Console.WriteLine("Respective Courses...");
foreach (var course in teacher.Courses)
{
Console.WriteLine("Course name : {0}", course.CourseName);
}
Console.WriteLine();
Console.ReadKey();
}
}
在上面的代码中,对表Teacher只进行了一次查询,由于该表只有8条记录,于是在内层循环中又分别产生了8次对表Course的查询。
在某些场合下,这种情况是可以接受的。你完全可以根据需要来控制内层循环何时显示加载数据,或者根本不加载数据。但是,在分层结构的应用程序中,上述代码结构并不适用,因为内层循环需要依赖于外层的Context,也就是说它们是在同一个数据库上下文中完成的,如果尝试将内层循环的代码移到外面或者其它类中,则它将获取不到任何数据。
显式加载(Explicit Loading)
如果你想人为控制惰性加载的行为,可以尝试使用下面的代码。首先需要手动关闭EF的惰性加载,通过代码ctx.Configuration.LazyLoadingEnabled = false;来完成。
using (var ctx = new SchoolDBEntities())
{
ctx.Configuration.LazyLoadingEnabled = false;
var q = from t in ctx.Teachers
select t;
foreach (var teacher in q)
{
Console.WriteLine("Teacher : {0}", teacher.TeacherName);
Console.WriteLine("Respective Courses...");
// Conditionally load the child data
if (true)
{
//高亮部分
ctx.Entry(teacher).Collection(c => c.Courses).Load();
}
foreach (var course in teacher.Courses)
{
Console.WriteLine("Course name : {0}", course.CourseName);
}
Console.WriteLine();
Console.ReadKey();
}
}
注意内层循环只有在上面高亮显示部分的代码执行之后才会获取到数据,否则返回结果为0。通过添加判断条件,我们可以对数据加载方式进行控制,从而有效地减少程序与数据库交互的次数。大多数情况下,我们从数据库获取到的数据并不都是有用的,如果每次只有很少一部分数据有用,那么我们为什么不过滤掉那些无用的数据从而尽量较少数据交互的次数呢?
预先加载(Eager Loading)
如果你想让所有数据全部一次性加载到内存中,那么你需要使用.Include(Entity)方法。看下面的代码:
using (var ctx = new SchoolDBEntities())
{
//数据全部一次性加载到内存
var q = from t in ctx.Teachers.Include("Courses")
select t;
foreach (var teacher in q)
{
Console.WriteLine("Teacher : {0}", teacher.TeacherName);
Console.WriteLine("Respective Courses...");
foreach (var course in teacher.Courses)
{
Console.WriteLine("Course name : {0}", course.CourseName);
}
Console.WriteLine();
Console.ReadKey();
}
}
如果你查看SQl Server Profiler中的跟踪信息,你会发现只有一次数据交互过程,即程序只通过一次查询便获取到了所有需要的数据。在分层结构中,该方法是最容易的,我们可以将数据库底层获取到的结果返回给上层,它不具有任何依赖项。同时,它也可以减少程序与数据库的交互次数。不过仍然有缺点,那就是如果数据量较大,一次性将所有数据载入内存往往并不是最明智的选择。.Include(Entity)方法允许级联使用,你可以预先加载具有多层级结构的数据。
总结
就像前面所说,选择什么样的数据加载方式需要因时而异,每一种数据加载方式都有它存在的意义,但目的只有一个,那就是以最少的代价获取到需要的数据。




近期评论