我有以下型号 -
public class Student
{
public int StudentID { get; set; }
public string StudentName { get; set; }
public Nullable<int> StandardId { get; set; }
public virtual Standard Standard { get; set; }
}
public class Standard
{
public int StandardId { get; set; }
public string StandardName { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
关系是 - &gt;一个标准可以有多个学生。 当使用IEnumerable执行以下代码时,它会执行延迟加载,如下面的日志所示
代码 -
using (var ctx = new SchoolDBEntities())
{
ctx.Database.Log = Logger.Log;
IEnumerable<Student> studList = ctx.Students;
foreach(Student std in studList)
{
Console.WriteLine("Student Name = " + std.StudentName);
//Loads Student standard for particular Student only (separate SQL query)
Standard standard = std.Standard;
Console.WriteLine("Standard Name = " + standard.StandardName);
}
}
从日志中可以看出&#34;标准&#34;表数据在需要时获取。 那么为什么说IEnumerable不支持Laze Loading和IQueryable呢?
当我使用IQueryable代替IEnumerable运行代码时,它会显示相同的日志。 我没有找到任何解释IEnumerable如何不支持延迟加载的例子。
答案 0 :(得分:9)
那么为什么说IEnumerable不支持Laze Loading
延迟加载是一个ORM概念(在您的情况下是实体框架) 您可以将其视为实现细节。
IEnumerable<T>
和IQueryable<T>
都不支持延迟加载。
IEnumerable<Student> studList = ctx.Students;
无论变量类型(IEnumerable<Student>
)如何,引用的对象类型将是DbSet<Student>
,它实现IQueryable<Student>
。
DbSet<T>
使用EF基础结构来实现对象。延迟加载由代理类型实现,由EF对象材质生成器生成。这不是IEnumerable<T>
或IQueryable<T>
功能。
P.S。
如上所述,延迟执行!=延迟加载。
IEnumerable<T>
和IQueryable<T>
支持延迟执行。对于IQueryable<T>
这意味着,将执行该查询,并且只有在您开始枚举查询结果时才会实现对象。
但这不是延迟加载。当您调用属性getter时,将加载Student.Standard
。这个是延迟加载。正如您所看到的,它与IQueryable<T>
有关:您不需要IQueryable<T>
来调用属性getter。
答案 1 :(得分:2)
这是关于运行时与编译时类型,以及集合与它包含的对象。
当您执行查询时,可以分配到IEnumerable<T>
变量,但它仍然是IQueryable<T>
下面的。{/ p>
但是,只要在其上使用IEnumerable<T>
方法,该集合就不再是可查询的。例如。致电ToArray
或ToList
。
这样做的主要影响是进一步的操作(例如,Where
进行过滤)将在内存中发生,而不是更改查询。
然而 这与EF关联的懒惰属性(代码中的std.Standard
无关)在集合中的单个对象上完成而不是收藏。
所以,如果你有
var qry = /* something to create an IQueryable<T> from your DbContent */
foreach (var x in qry) {
// qry has been enumerated: so SQL has been generated and executed
}
qry = qry.Where(some-condition);
foreach (var x in qry) {
// qry has been enumerated: SQL with extra condition applied is run
}
var e = qry.ToList();
// Anything done to e is done in memory, there will be no new
// SQL sent to the DB for the collection/
var f = e.First();
// But, as Standard is a lazy property this will generated a query.
x = e.Standard.SomeProperty;
答案 2 :(得分:-1)
这只是我的猜测,如果我错了,我会很乐意纠正。
我所知道的,IQueryable
继承自IEnumerable
。使用数据库上下文时的底层类型应为IQueryable
- 这也可以启用延迟加载。
您始终可以将IQueryable
转换为IEnumerable
(反之亦然,通过扩展方法)。 IQueryable
的优点是LL - 您可以对查询执行操作/过滤而无需立即执行。这在处理大量数据时非常有用。