IEnumerable 和延迟加载
IEnumerable and Lazy loading
我有以下型号 -
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; }
}
关系是->一个标准可以有多个学生。
当使用 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);
}
}
日志-
从日志中可以看出,"Standard" table 数据是在需要的时候取的。
那为什么说IEnumerable不支持Laze Loading而IQueryable支持呢?
当我 运行 使用 IQueryable 代替 IEnumerable 的代码时,它显示相同的日志。
我没有找到任何示例来解释 IEnumerable 如何不支持延迟加载。
这只是我的猜测,如果我错了,我很乐意得到纠正。
据我所知,IQueryable
继承自 IEnumerable
。使用数据库上下文时的底层类型应该是 IQueryable
- 这也启用了延迟加载。
您始终可以将 IQueryable
转换为 IEnumerable
(反之亦然,通过扩展方法)。 IQueryable
的优点是 LL - 您可以对查询执行 operations/filtering 而无需立即执行。这在处理大量数据时非常有用。
Then why it is said that IEnumerable does not support Laze Loading
延迟加载是一个 ORM 概念(Entity Framework 在你的例子中)。
您可以将其视为实现细节。
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>
这意味着,将执行该查询,并且仅当您开始枚举查询结果时才会具体化对象。
但这不是延迟加载。 Student.Standard
将在您调用 属性 getter 时加载。这个是延迟加载。如您所见,它与 IQueryable<T>
无关:您不需要 IQueryable<T>
来调用 属性 getter.
这是关于运行时类型与编译时类型,以及集合与它包含的对象。
当您执行查询时可以分配给一个 IEnumerable<T>
变量,它仍然是一个 IQueryable<T>
下面。
但是,一旦您对其使用 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;
我有以下型号 -
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; }
}
关系是->一个标准可以有多个学生。 当使用 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);
}
}
日志-
从日志中可以看出,"Standard" table 数据是在需要的时候取的。 那为什么说IEnumerable不支持Laze Loading而IQueryable支持呢?
当我 运行 使用 IQueryable 代替 IEnumerable 的代码时,它显示相同的日志。 我没有找到任何示例来解释 IEnumerable 如何不支持延迟加载。
这只是我的猜测,如果我错了,我很乐意得到纠正。
据我所知,IQueryable
继承自 IEnumerable
。使用数据库上下文时的底层类型应该是 IQueryable
- 这也启用了延迟加载。
您始终可以将 IQueryable
转换为 IEnumerable
(反之亦然,通过扩展方法)。 IQueryable
的优点是 LL - 您可以对查询执行 operations/filtering 而无需立即执行。这在处理大量数据时非常有用。
Then why it is said that IEnumerable does not support Laze Loading
延迟加载是一个 ORM 概念(Entity Framework 在你的例子中)。
您可以将其视为实现细节。
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>
这意味着,将执行该查询,并且仅当您开始枚举查询结果时才会具体化对象。
但这不是延迟加载。 Student.Standard
将在您调用 属性 getter 时加载。这个是延迟加载。如您所见,它与 IQueryable<T>
无关:您不需要 IQueryable<T>
来调用 属性 getter.
这是关于运行时类型与编译时类型,以及集合与它包含的对象。
当您执行查询时可以分配给一个 IEnumerable<T>
变量,它仍然是一个 IQueryable<T>
下面。
但是,一旦您对其使用 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;