IEnumerable和Lazy加载

Jit*_*hal 2 .net c# 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; }
}
Run Code Online (Sandbox Code Playgroud)

关系是 - >一个标准可以有多个学生.当使用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);
  }
}
Run Code Online (Sandbox Code Playgroud)

日志 - 日志 -

从日志中可以看出,在需要时提取"标准"表数据.那么为什么说IEnumerable不支持Laze Loading和IQueryable呢?

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

Den*_*nis 10

那么为什么说IEnumerable不支持Laze Loading

延迟加载是ORM概念(在您的情况下是实体框架).
您可以将其视为实现细节.

既不支持IEnumerable<T>也不IQueryable<T>支持延迟加载.

IEnumerable<Student> studList = ctx.Students;
Run Code Online (Sandbox Code Playgroud)

无论变量 type(IEnumerable<Student>)如何,引用的对象类型都将DbSet<Student>实现IQueryable<Student>.

DbSet<T>使用EF基础设施来实现对象.延迟加载由代理类型实现,由EF对象材质生成器生成.这不是IEnumerable<T>或没有IQueryable<T>特色.

PS

如上所述,延迟执行!=延迟加载.

IEnumerable<T>IQueryable<T>支持延期执行.对于IQueryable<T>这意味着,查询将被执行,对象将被物化,只有当你将开始枚举查询结果.

但这不是延迟加载.Student.Standard将被加载,当你打电话给属性getter.这延迟加载.正如您所看到的,它与之相关IQueryable<T>:您不需要IQueryable<T>调用属性getter.


Ric*_*ard 5

这是关于运行时与编译时类型,以及集合与它包含的对象。

当您执行查询可以分配给一个IEnumerable<T>变量时,它仍然是一个IQueryable<T>底层。

但是,一旦您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;
Run Code Online (Sandbox Code Playgroud)