发布网友 发布时间:2022-04-21 17:32
共1个回答
热心网友 时间:2022-04-09 23:11
先简单说一下如何创建环境。如果你对这些步骤了如指掌,请直接跳过。
1. 在Visual Studio中创建一个示例工程。最简单的莫过于ConsoleApplication
2. 在工程中添加ADO.NET Entity Data Model。
选择其中的两个表作为示例,表Teacher和表Course
添加edmx之后,Visual
Studio为自动帮我们生成/添加所有需要的文件和内容,然后我们就可以开始在代码中操作数据库了。来看看在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();
}
}
下面是程序执行的结果以及在SQL Server
Profiler中的跟踪记录。可以清楚地看到,对表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)方法允许级联使用,你可以预先加载具有多层级结构的数据。