1、测试一下:只查询,但是不遍历IQueryable,查看是否有执行SQL语句。
2、在查询之后、foreach前后分别加上输出语句,查看输出内容的顺序。
3、发现:只有遍历IQueryable的时候才会执行。
输出的顺序:准备where 准备foreach 执行查询语句 完成foreach
什么是IQueryable
1、IQueryable只是代表一个“可以放到数据库服务器去执行的查询”,它没有立即执行,只是“可以被执行”而已。
2、对于IQueryable接口调用非终结方法的时候不会执行查询,而调用终结方法的时候则会立即执行查询。
3、终结方法:遍历、ToArray()、ToList()、Min()、Max()、Count()等;
4、非终结方法:GroupBy()、OrderBy()、Include()、Skip()、Take()等。
5、简单判断:一个方法的返回值类型如果是IQueryable类型,那么这个方法一般就是非终结方法,否则就是终结方法。
附: List泛型集合是C#编程中的经常使用的集合之一,相对数组它可以动态的添加元素而不是声明的时候就必须指定大小。相对于ArrayList集合和Hashtable集合的优势是其元素的数据类型可以确定。而不是默认的父类类型object。
为什么要延迟执行?
说白了就是,在你把最终结果取出来之前,EF要想写一个sql就完事了,不和你逼逼,一次性干完活。
1、可以在实际执行之前,分步构建IQueryable。
2、比如:定义一个方法根据给定的关键字searchWords来查询匹配的书;如果searchAll参数是true,则书名或者作者名中含有给定的searchWords都匹配,否则只匹配书名;如果orderByPrice参数为true,则按照价格排序,否则就自然排序;upperPrice参数代表价格上限。
void QueryBooks(string searchWords, bool searchAll, bool orderByPrice,double upperPrice)
3、试着传递不同参数,查看生成的SQL的不同。
private static void QueryBooks(string searchWords, bool searchAll, bool orderByPrice,double upperPrice)
{
using (TestDbContext ctx = new TestDbContext())
{
IQueryable<Book> books = ctx.Books.Where(b=>b.Price<=upperPrice);
if(searchAll)//匹配书名或、作者名
{
books = books.Where(b=>b.Title.Contains(searchWords)|| b.AuthorName.Contains(searchWords));
}
else//只匹配书名
{
books = books.Where(b => b.Title.Contains(searchWords));
}
if(orderByPrice)//按照价格排序
{
books = books.OrderBy(b=>b.Price);
}
foreach(Book b in books)
{
Console.WriteLine($"{b.Id},{b.Title},{b.Price},{b.AuthorName}");
}
}
}
结论
IQueryable代表一个对数据库中数据进行查询的一个逻辑,这个查询是一个延迟查询。我们可以调用非终结方法向IQueryable中添加查询逻辑,当执行终结方法的时候才真正生成SQL语句来执行查询。
可以实现以前要靠SQL拼接实现的动态查询逻辑。
思考:对IQueryable的复用
1、IQueryable是一个待查询的逻辑,因此它是可以被重复使用的。
2、
IQueryable<Book> books = ctx.Books.Where(b => b.Price <= 8);
Console.WriteLine(books.Count());
Console.WriteLine(books.Max(b=>b.Price));
var books2 = books.Where(b=>b.PubTime.Year>2000);
有一说一这个🈵️有用的,似乎可以试试,减少代码重复量。