zoukankan      html  css  js  c++  java
  • Entity Framework中IQueryable, IEnumerable, IList的差别

    应用Entity Framework等ORM框架的时辰,SQL对于应用者来说是透明的,往往很多人也不关怀ORM所生成的SQL,然而体系呈现机能题目的时辰就必须存眷生成的SQL以发明题目地点。

    应用过Toplink的伴侣知道很只要设置日记打印级别=FINE就可以设备使之生成的SQL在办事器中打印出来,Entiry Framework没有那么荣幸,在以前要检测生成SQL的独一办法是SQL Server Profiler,但应用起来并不便利,成果也不克不及主动保存到文件中。

    Tracing and Caching Provider Wrappers for Entity Framework是Entity Framework Team新推出的开源SQL追踪和二级缓存的解决规划。道理是在负责履行具体SQL语句的data provider(SqlClient或者其他Client)之上插入了一层WrappingProvider,用于监控DbCommand.uteReader(), uteScalar() and uteNonQuery(),将Sql号令输出到指定介质或者将查询成果缓存起来以重用。

    应用办法很简单,下载源代码编译后将dll添加到项目中,新加一个类WrappedNorthWindEntities持续原有的Entities即可,详见源代码中的示例。

    下面我们应用EF Wrapper来监测Entify Framework中IQueryable, IEnumerable和IList所生成的SQL。

    TestIQueryable 

    private static void TestIQueryable()
    {

    using (var ctx = new WrappedNorthWindEntities())
    {
    IQueryable<Product> expression = ctx.Products.Take(5);
    IQueryable<Product> products = expression.Take(2); // A 不履行SQL


    Console.WriteLine(products.Count());          // B SELECT COUNT(1) FROM ( SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] ))
    Console.WriteLine(products.Count());          // C SELECT COUNT(1) FROM ( SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] ))
    foreach (Product p in products)             // D SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products]
    {
    Console.WriteLine(p.ProductName);
    }
    foreach (Product p in products)             // E SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] )
    {
    Console.WriteLine(p.ProductName);
    }
    }
    }
    TestIEnumerable 

    private static void TestIEnumerable()
    {
    using (var ctx = new WrappedNorthWindEntities())
    {
    IEnumerable<Product> expression = ctx.Products.Take(5).AsEnumerable();
    IEnumerable<Product> products = expression.Take(2); // A 不履行SQL
    Console.WriteLine(products.Count());          // B SELECT TOP (5) * FROM [dbo].[Products]
    Console.WriteLine(products.Count());          // C SELECT TOP (5) * FROM [dbo].[Products]
    foreach (Product p in products)             // D SELECT TOP (5) * FROM [dbo].[Products]
    {
    Console.WriteLine(p.ProductName);
    }
    foreach (Product p in products)             // E SELECT TOP (5) * FROM [dbo].[Products]
    {
    Console.WriteLine(p.ProductName);
    }
    }
    }
    TestIList 

    private static void TestIList()
    {
    using (var ctx = new WrappedNorthWindEntities())
    {
    var expression = ctx.Products.Take(5);
    IList<Product> products = expression.Take(2).ToList(); // A SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products]


    Console.WriteLine(products.Count());           // B 不履行SQL
    Console.WriteLine(products.Count());           // C 不履行SQL
    foreach (Product p in products)              // D 不履行SQL
    {
    Console.WriteLine(p.ProductName);
    }
    foreach (Product p in products)             // E 不履行SQL
    {
    Console.WriteLine(p.ProductName);
    }
    }
    }

     由上可见



      1. IQueryable和IEnumerable都是延时履行(Deferred ution)的,而IList是即时履行(Eager ution)
      1. IQueryable和IEnumerable在每次履行时都必须连接数据库读取,而IList读取一次后,今后各次都不需连接数据库。前两者很轻易造成反复读取,机能低下,并且可能激发数据不一致性
      1. IQueryable和IEnumerable的差别:IEnumberalb应用的是LINQ to Object体式格式,它会将AsEnumerable()时对应的所有记录都先加载到内存,然后在此根蒂根基上再履行后来的Query。所以上述TestIEnumerable例子中履行的SQL是" top(5) ...",然后在内存中选择前两笔记录返回。



    IQueryable激发数据不一致性的例子:记录总数和记录详情两者本应一致,但因为IQueryable前后两次读取数据库,成果是实际有10笔记录,却输出11条详情。

    IQueryable Data Inconsistancy 

        IQueryable<Product> expression = ctx.Products.All();
    //开端的时辰数据库product表中有10笔记录, count = 10
    int count = products.Count();
    Console.WriteLine("Count of products:"+count);

            
    //此时另一过程添加一个产品进数据库

        //会从头读取数据库并输出11个产品名称
    foreach (Product p in products)
    {
    Console.WriteLine(p.ProductName);
    }

    基于机能和数据一致性这两点,我们应用IQueryable时必须谨慎,而在大多半景象下我们应应用IList。



      • 当你筹算即速应用查询后的成果(比如轮回作逻辑处理惩罚或者填充到一个table/grid中),并且你不介怀该查询会即时履行,应用ToList()
      • 当你欲望查询后的成果可以供调用者(Consummer)作后续查询(比如这是一个"GetAll"的办法),或者你欲望该查询延时履行,应用AsQueryable()
  • 相关阅读:
    DEV获取GridControl当前行
    03002_Http请求协议分析
    雷林鹏分享:CSS 组合选择符
    雷林鹏分享:Redis 字符串(String)
    雷林鹏分享:Redis 键(key)
    雷林鹏分享:CSS 布局
    雷林鹏分享:CSS Float(浮动)
    雷林鹏分享:CSS 布局
    雷林鹏分享:CSS Position(定位)
    雷林鹏分享:CSS Display(显示) 与 Visibility(可见性)
  • 原文地址:https://www.cnblogs.com/zhangchenliang/p/2810540.html
Copyright © 2011-2022 走看看