IEnumerable和Lazy加载

时间:2018-01-15 12:39:53

标签: c# .net collections ienumerable iqueryable

我有以下型号 -

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);
  }
}

日志 - Logs-

从日志中可以看出&#34;标准&#34;表数据在需要时获取。 那么为什么说IEnumerable不支持Laze Loading和IQueryable呢?

当我使用IQueryable代替IEnumerable运行代码时,它会显示相同的日志。 我没有找到任何解释IEnumerable如何不支持延迟加载的例子。

3 个答案:

答案 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>方法,该集合就不再是可查询的。例如。致电ToArrayToList

这样做的主要影响是进一步的操作(例如,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 - 您可以对查询执行操作/过滤而无需立即执行。这在处理大量数据时非常有用。