EntityFramework-虚拟ICollection查询

时间:2019-04-12 17:14:41

标签: c# sql entity-framework entity-framework-6

我有这样的实体:

public class Student
{
    public int StudentId { get; set; }
    public string StudentName { get; set; }

    //Foreign key for Standard
    public 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; }
}

在我的查询中,我写的是:

dbcontext.Standards.Where(standard => standard.StandardId > 6)

我可以看到已经运行的基础查询类似于:

SELECT "Extent1"."StandardId", "Extent1"."StandardName"
FROM "dbo"."Standard" as "Extent1"
WHERE "Extent1"."StandardId" > @EntityKeyValue1;

我了解到,因为它是IQueryable的,所以甚至表达式Where in函数也已翻译并且实际上在数据库而不是程序中运行。

由于我已将收藏集标记为虚拟,因此未加载学生。不,我正在尝试在另一个查询中加载它们:

var XStandard = dbcontext.Standards.Where(standard => standard.StandardId == 10);
var students = XStandard.Students.Where(student => student.StudentId > 5);

我看到执行的查询是:

SELECT "Extent1"."StudentId", "Extent1"."StudentName", "Extent1"."StandardId"
FROM "dbo"."Student" as "Extent1"
WHERE "Extent1"."StandardId = @EntityKeyValue1;

我在该查询中没有看到任何WHERE子句,该子句检查学生ID大于5。它实际上是在提取所有学生并在内存中过滤。我了解这是因为它是IEnumerable而不是IQueryable,并且因为IEnumerable是LINQ到对象,所以过滤是在内存中完成的。

当我像这样对dbcontext运行查询时:

var students = dbcontext.Students.Where(student => student.StudentId > 5 && student.StandardId == 10);

现在,SQL查询就像:

SELECT "Extent1"."StudentId", "Extent1"."StudentName", "Extent1"."StandardId"
FROM "dbo"."Student" as "Extent1"
WHERE "Extent1"."StandardId" = @EntityKeyValue1 AND "Extent1"."StudentId" > @EntityKeyValue2;

如果对嵌套集合的查询获取所有记录而不是少数几个记录,那么在一对多关系中嵌套集合的意义何在? 有没有一种方法可以确保它在数据库端运行?我想念什么吗?请帮助我了解EF如何在内部工作。预先感谢。

2 个答案:

答案 0 :(得分:0)

您正在使用延迟加载。 在延迟加载的情况下,相关对象(子对象)在请求之前不会自动与其父对象一起加载。默认情况下,LINQ支持延迟加载。 也许这可以帮助您确定: Lazy Loading vs Eager Loading

答案 1 :(得分:0)

遇到同样的问题。我认为您在这里需要的是显式加载嵌套集合。

dbcontext.Entry(XStandard).Collection(c => c.Students).Query().Where(student => student.StudentId > 5).Load();

之后,Where子句中的条件应该被翻译成SQL。

https://docs.microsoft.com/en-us/ef/ef6/querying/related-data?redirectedfrom=MSDN#Applying-filters-when-explicitly-loading-related-entities

但您肯定需要检索过滤后的集合,如文档中所述:

<块引用>

使用 Query 方法时,通常最好关闭导航属性的延迟加载。这是因为否则整个集合可能会在执行过滤查询之前或之后被延迟加载机制自动加载。