EntityFramework优化:查询性能

1. 禁用延迟加载

  延迟加载是常见的方式,Entity Framework在需要时可以自动为一个实体的实例获取关联的数据。

  Entity Framework自动延迟加载需要同时满足以下3个条件:

  (1)DbContext.Configuration.LazyLoadingEnabled = true (默认为true)

  (2)DbContext.Configuration.ProxyCreationEnabled = true (默认为true)

  (3)POCO类必须是public而非sealed,且集合属性使用Virtual修饰,这样Entity Framework才能Override以包含延迟加载。

  延迟加载示例:

using (var ctx = new LibingContext())
{
    var category = ctx.Categories.Find(1);
    foreach (var product in category.Products)
    {
        Console.WriteLine(product.ProductName);
    }
}

  EntityFramework禁用延迟加载:

public class LibingContext : DbContext
{
    public LibingContext()
        : base("Name=LibingContext")
    {
        // 禁用延迟加载
        this.Configuration.LazyLoadingEnabled = false;
        this.Configuration.ProxyCreationEnabled = false;
    }
}

2. AsNoTracking()与Attach()

  对于只读操作,强烈建议使用AsNoTracking进行数据获取,降低数据获取所需的时间。

  由于没有受到DbContext的跟踪,利于对数据及时性要求高的数据查询。

  使用AsNoTracking查询出来的数据,要进行删除时,需使用Attach()。

using (var ctx = new LibingContext())
{
    var products = ctx.Products
        .AsNoTracking()
        .ToList();

    var product = products.Where(t => t.ProductID == 1).FirstOrDefault();

    //// 修改不用Attach
    //product.ProductName = "新名称";
    //ctx.Entry(product).State = EntityState.Modified;

    ctx.Set<Product>().Attach(product);
    ctx.Entry(product).State = EntityState.Deleted;

    ctx.SaveChanges();
}

  注:查询过程Select映射不需要加AsNoTracking()

var products = ctx.Products
    .Select(t => new { t.ProductID, t.ProductName })
    .ToList();

3. AsNonUnicode

using (var ctx = new LibingContext())
{
    var products = ctx.Products
        .Where(t => t.ProductName == "商品")
        .ToList();
}
SELECT 
    [Extent1].[ProductID] AS [ProductID], 
    [Extent1].[CategoryID] AS [CategoryID], 
    [Extent1].[ProductName] AS [ProductName], 
    [Extent1].[UnitPrice] AS [UnitPrice], 
    [Extent1].[UnitsInStock] AS [UnitsInStock]
    FROM [dbo].[Product] AS [Extent1]
    WHERE N'商品' = [Extent1].[ProductName]
using System.Data.Entity;
using (var ctx = new LibingContext())
{
    var products = ctx.Products
        .Where(t => t.ProductName == DbFunctions.AsNonUnicode("商品"))
        .ToList();
}
SELECT 
    [Extent1].[ProductID] AS [ProductID], 
    [Extent1].[CategoryID] AS [CategoryID], 
    [Extent1].[ProductName] AS [ProductName], 
    [Extent1].[UnitPrice] AS [UnitPrice], 
    [Extent1].[UnitsInStock] AS [UnitsInStock]
    FROM [dbo].[Product] AS [Extent1]
    WHERE '商品' = [Extent1].[ProductName]

  EF正常情况生成的SQL会在前面带上“N”,加上DbFunctions.AsNonUnicode生成的SQL没有“N”。“N”是将字符串作为Unicode格式进行存储。

  .Net字符串是Unicode格式,SQL中带“N”会进行数据转换,无法使用索引,只能全表扫描。

  DbFunctions.AsNonUnicode()让.Net将其作为一个非Unicode来处理。

  在进行字符串查找或者比较时建议用AsNonUnicode()方法来提高查询性能。

4. 使用AutoMapper查询DTO

  查询需要的字段:DTO

using AutoMapper;
using AutoMapper.QueryableExtensions;
using (var ctx = new LibingContext())
{
    Mapper.Initialize(cfg => cfg.CreateMap<Product, ProductDTO>());

    var products = ctx.Products
        .ProjectTo<ProductDTO>()
        .ToList();
}
posted @ 2018-05-19 16:17  libingql  阅读(935)  评论(0编辑  收藏  举报