第二篇 Entity Framework Plus 之 Query Future IEnumerable 和 IQueryable 第一篇 Entity Framework Plus 之 Audit

  從性能的角度出發,可以減小 增,刪,改,查,跟數據庫打交道次數,確定是對性能會有所提高的(這裏單純是數據庫部分)。html

 今天主要怎樣減小Entity Framework查詢跟數據庫打交道的次數,來提升查詢性能。git

 舉一個你們最經常使用功能 「分頁」 功能。先貼一段代碼。github

       private static IEnumerable<OrderModel> FindPagerOrders(int pageSize, int pageIndex, out int totalCount) { using (var dbContext = new EntityFrameworkPlusDbContext()) { var orders = dbContext.Orders.OrderBy(o => o.CreateDateTime); totalCount = orders.Count(); var pagerOrders = orders.Skip((pageIndex - 1) * pageSize).Take(pageSize); return pagerOrders .ToList(); } }

這類型的代碼,你們估計都看到過,也本身寫過,簡單分析一下。數據庫

 orders.Count() 返回int 類型,確定要查詢出數據庫才知道訂單總筆數。app

 pagerOrders.ToList() 返回  IEnumerable<T> 類型,這個不用解釋Entity Framework  IEnumerable 和 IQueryable 區別是ide

 IEnumerable 會執行SQL,IQueryable 而不會。因此這句也會去數據庫查詢一次。post

那整個分頁功能用Entity Framework 就是最少要兩次數據庫查詢,剛剛上面說了,一個基本的提升性能方法就要減小與數據庫打交道次數。性能

從「分頁」功能來講,要是變成只有一次與數據庫打交道,那就是對性能有大提高。Entity Framework 自身是沒有提供這樣的方法。ui

    Entity Framework Plus 庫 Query Future 擴展,是一個對Entity Framework 功能的延伸和擴展,可以作到減小數據庫打交道次數。使查詢性能更高。this

 一 . Entity Framework Plus 庫 Query Future 安裝

1.  解決方案 仍是我上一篇 第一篇 Entity Framework Plus 之 Audit 用的解決方案「EntityFrameworkPlusSolution」,新增 「EntityFrameworkPlus.QueryFuture.Demo」 控制檯項目,做爲Entity Framework Plus 庫 Query Future 擴展 應用和展現功能項目。項目結構截圖以下

 

項目關係圖 (代碼圖)

2. 爲了方便Demo,新增商品業務 相關的 Model,Mapping,以及改動DbContext 以下代碼

GoodsModel

using System; namespace EntityFrameworkPlus.Models { public class GoodsModel { public System.Guid GoodsGuid { get; set; } public string GoodsNo { get; set; } public string GoodsName { get; set; } public string GoodsBrand { get; set; } public decimal UnitPrice { get; set; } public string Description { get; set; } public string Creator { get; set; } public System.DateTime CreateDateTime { get; set; } public string LastModifier { get; set; } public DateTime? LastModifiedDateTime { get; set; } } }

GoodsMap

using System.Data.Entity.ModelConfiguration; using EntityFrameworkPlus.Models; namespace EntityFrameworkPlus.Mappings { public class GoodsMap: EntityTypeConfiguration<GoodsModel> { public GoodsMap() { // Primary Key
            this.HasKey(t => t.GoodsGuid); // Properties
            this.Property(t => t.GoodsNo) .IsRequired() .HasMaxLength(50); this.Property(t => t.GoodsName) .IsRequired() .HasMaxLength(50); this.Property(t => t.GoodsBrand) .IsRequired() .HasMaxLength(50); this.Property(t => t.Creator) .IsRequired() .HasMaxLength(20); this.Property(t => t.LastModifier) .HasMaxLength(20); // Table & Column Mappings
            this.ToTable("Sample_Goods"); this.Property(t => t.GoodsGuid).HasColumnName("GoodsGuid"); this.Property(t => t.GoodsNo).HasColumnName("GoodsNo"); this.Property(t => t.GoodsName).HasColumnName("GoodsName"); this.Property(t => t.GoodsBrand).HasColumnName("GoodsBrand"); this.Property(t => t.UnitPrice).HasColumnName("UnitPrice"); this.Property(t => t.Description).HasColumnName("Description"); this.Property(t => t.Creator).HasColumnName("Creator"); this.Property(t => t.CreateDateTime).HasColumnName("CreateDateTime"); this.Property(t => t.LastModifier).HasColumnName("LastModifier"); this.Property(t => t.LastModifiedDateTime).HasColumnName("LastModifiedDateTime"); } } }

EntityFrameworkPlusDbContext 

using System.Data.Entity; using EntityFrameworkPlus.Mappings; using EntityFrameworkPlus.Models; using Z.EntityFramework.Plus; namespace EntityFrameworkPlus.DbContext { public class EntityFrameworkPlusDbContext : System.Data.Entity.DbContext { public EntityFrameworkPlusDbContext() : base("EntityFrameworkPlusConnection") { } public DbSet<AuditEntry> AuditEntries { get; set; } public DbSet<AuditEntryProperty> AuditEntryProperties { get; set; } public DbSet<OrderModel> Orders { get; set; } public DbSet<GoodsModel> Goodses { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new OrderMap()); modelBuilder.Configurations.Add(new GoodsMap()); base.OnModelCreating(modelBuilder); } } }

3. 右鍵 「EntityFrameworkPlus.QueryFuture.Demo」 項目,選擇「管理NuGet程序包」,關聯部分  右上角搜索「Z.EntityFramework.Plus」 ,而後選擇 「EntityFramework Plus (EF6) | Query Deferred」&「EntityFramework Plus (EF6) | Query Futurn」 兩項安裝

二. Entity Framework Plus  庫 Query Future 擴展功能實做

1. 在 「EntityFrameworkPlus.QueryFuture.Demo」 項目 Program 新增3個靜態方法,分別是 

FindOrdersWithGoodsies()  查詢訂單信息和商品信息

FindPagerOrders(int pageSize, int pageIndex, out int totalCount)  訂單分頁查詢

FindGoodsMaxWithMinUnitPrice() 查詢單價最大和最小的商品

詳細代碼以下

using System.Collections.Generic; using System.Linq; using EntityFrameworkPlus.DbContext; using EntityFrameworkPlus.Models; using Z.EntityFramework.Plus; namespace EntityFrameworkPlus.QueryFuture.Demo { class Program { static void Main(string[] args) { //1.查詢訂單信息和商品信息
 FindOrdersWithGoodsies(); //2. 訂單分頁查詢 //var totalCount = 0; //FindPagerOrders(10, 1, out totalCount); //3.查詢單價最大和最小的商品 //FindGoodsMaxWithMinUnitPrice();
 } private static void FindOrdersWithGoodsies() { using (var dbContext = new EntityFrameworkPlusDbContext()) { var futureOrders = dbContext.Orders.Future(); var futureGoodsies = dbContext.Goodses.Future(); var orders = futureOrders.ToList(); var goodsies = futureGoodsies.ToList(); } } private static IEnumerable<OrderModel> FindPagerOrders(int pageSize, int pageIndex, out int totalCount) { using (var dbContext = new EntityFrameworkPlusDbContext()) { var orders = dbContext.Orders.OrderBy(o => o.CreateDateTime); var futureCount = orders.DeferredCount().FutureValue(); var futurePagerOrders = orders.Skip((pageIndex - 1) * pageSize).Take(pageSize).Future(); totalCount = futureCount.Value; return futurePagerOrders.ToList(); } } private static void FindGoodsMaxWithMinUnitPrice() { using (var dbContext = new EntityFrameworkPlusDbContext()) { var futureMaxGoodsUnitPrice = dbContext.Goodses.DeferredMax(g => g.UnitPrice).FutureValue<decimal>(); var futureMinGoodsUnitPrice = dbContext.Goodses.DeferredMin(g => g.UnitPrice).FutureValue<decimal>(); var maxGoodsUnitPrice = futureMaxGoodsUnitPrice.Value; var minGoodsUnitPrice = futureMaxGoodsUnitPrice.Value; } } } }

2.  3個方法的SQL追蹤和截圖

FindOrdersWithGoodsies
-- EF+ Query Future: 1 of 2
SELECT 
    [Extent1].[OrderGuid] AS [OrderGuid], [Extent1].[OrderNo] AS [OrderNo], [Extent1].[OrderCreator] AS [OrderCreator], [Extent1].[OrderDateTime] AS [OrderDateTime], [Extent1].[OrderStatus] AS [OrderStatus], [Extent1].[Description] AS [Description], [Extent1].[Creator] AS [Creator], [Extent1].[CreateDateTime] AS [CreateDateTime], [Extent1].[LastModifier] AS [LastModifier], [Extent1].[LastModifiedDateTime] AS [LastModifiedDateTime]
    FROM [dbo].[Sample_Order] AS [Extent1]


-- EF+ Query Future: 2 of 2
SELECT 
    [Extent1].[GoodsGuid] AS [GoodsGuid], [Extent1].[GoodsNo] AS [GoodsNo], [Extent1].[GoodsName] AS [GoodsName], [Extent1].[GoodsBrand] AS [GoodsBrand], [Extent1].[UnitPrice] AS [UnitPrice], [Extent1].[Description] AS [Description], [Extent1].[Creator] AS [Creator], [Extent1].[CreateDateTime] AS [CreateDateTime], [Extent1].[LastModifier] AS [LastModifier], [Extent1].[LastModifiedDateTime] AS [LastModifiedDateTime]
    FROM [dbo].[Sample_Goods] AS [Extent1]

FindPagerOrders(int pageSize, int pageIndex, out int totalCount)

-- EF+ Query Future: 1 of 2
SELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        COUNT(1) AS [A1]
        FROM [dbo].[Sample_Order] AS [Extent1] ) AS [GroupBy1]


-- EF+ Query Future: 2 of 2
SELECT 
    [Extent1].[OrderGuid] AS [OrderGuid], [Extent1].[OrderNo] AS [OrderNo], [Extent1].[OrderCreator] AS [OrderCreator], [Extent1].[OrderDateTime] AS [OrderDateTime], [Extent1].[OrderStatus] AS [OrderStatus], [Extent1].[Description] AS [Description], [Extent1].[Creator] AS [Creator], [Extent1].[CreateDateTime] AS [CreateDateTime], [Extent1].[LastModifier] AS [LastModifier], [Extent1].[LastModifiedDateTime] AS [LastModifiedDateTime]
    FROM [dbo].[Sample_Order] AS [Extent1]
    ORDER BY [Extent1].[CreateDateTime] ASC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY 

FindGoodsMaxWithMinUnitPrice()

-- EF+ Query Future: 1 of 2
SELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        MAX([Extent1].[UnitPrice]) AS [A1]
        FROM [dbo].[Sample_Goods] AS [Extent1] ) AS [GroupBy1]


-- EF+ Query Future: 2 of 2
SELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        MIN([Extent1].[UnitPrice]) AS [A1]
        FROM [dbo].[Sample_Goods] AS [Extent1] ) AS [GroupBy1]

至此比較經常使用到場景,就已經實做完成,你們看到截圖和SQL說明都是一次執行,其餘你們能夠根據 EntityFramework Plus 源代碼和文檔(不過是英文,可是基本可以看懂),進行更加深刻的瞭解,瞭解實現原理,我這裏仍是拋磚引玉一下。

這篇博文的源代碼:https://github.com/haibozhou1011/EntityFramework-PlusSample

相關文章
相關標籤/搜索