简体   繁体   English

实体框架查询太慢了

[英]Entity Framework query too slow

I am new to entity framework and love the simplicity but am having some trouble with speed. 我是实体框架的新手,喜欢简单,但速度有些麻烦。 I think I might be using the lazy loading incorrectly but having a hard time wrapping my head around it. 我想我可能会错误地使用延迟加载,但很难绕过它。 I have separated my data model layer and business entity layer, and use a function to create the business entity from my data model. 我已将数据模型层和业务实体层分开,并使用函数从我的数据模型中创建业务实体。 In this function I iterate over the different nested entities to create their corresponding models. 在这个函数中,我迭代不同的嵌套实体来创建它们相应的模型。 Ok, enough rambling here is some code: 好吧,这里有足够的漫游是一些代码:

IM_ITEM.cs (Product data model) IM_ITEM.cs(产品数据模型)

public partial class IM_ITEM
{
    public IM_ITEM()
    {
        this.IM_INV = new HashSet<IM_INV>();
        this.IM_BARCOD = new HashSet<IM_BARCOD>();
        this.IM_GRID_DIM_1 = new HashSet<IM_GRID_DIM_1>();
        this.IM_GRID_DIM_2 = new HashSet<IM_GRID_DIM_2>();
        this.IM_GRID_DIM_3 = new HashSet<IM_GRID_DIM_3>();
        this.IM_PRC = new HashSet<IM_PRC>();
    }

    public string ITEM_NO { get; set; }
    public string DESCR { get; set; }
    // many more properties...

    public virtual ICollection<IM_INV> IM_INV { get; set; }
    public virtual ICollection<IM_BARCOD> IM_BARCOD { get; set; }
    public virtual ICollection<IM_GRID_DIM_1> IM_GRID_DIM_1 { get; set; }
    public virtual ICollection<IM_GRID_DIM_2> IM_GRID_DIM_2 { get; set; }
    public virtual ICollection<IM_GRID_DIM_3> IM_GRID_DIM_3 { get; set; }
    public virtual ICollection<IM_PRC> IM_PRC { get; set; }
}

Business entity creation method: 业务实体创建方法:

public static ProductEntity FromEfObject(IM_ITEM obj) {
    var product = new ProductEntity {
        ItemNumber = obj.ITEM_NO,
        StyleNumber = obj.VEND_ITEM_NO,
        Title = obj.DESCR_UPR,
        LongName = obj.ADDL_DESCR_1,
        ShortDescription = obj.DESCR,
        VendorCode = obj.ITEM_VEND_NO,
        Quarter = obj.ATTR_COD_2,
        Color = obj.PROF_ALPHA_2,
        Markdown = obj.PRC_1,
        Price = obj.REG_PRC ?? 0,
        Status = obj.STAT,
        DepartmentCode = obj.ATTR_COD_1,
        DepartmentDigit = obj.ATTR_COD_1.Substring(0, 1),
        MixAndMatch = obj.MIX_MATCH_COD,
        Inventory = new Inventory(obj.IM_INV),
        Sizes = new List<ProductSize>(),
        Widths = new List<ProductSize>(),
        Lengths = new List<ProductSize>(),
        Barcodes = new Dictionary<string, string>()
    };


    if (obj.IM_PRC.Any()) {
        var price = obj.IM_PRC.First();
        product.DnsPrice2 = price.PRC_2.GetValueOrDefault();
        product.DnsPrice3 = price.PRC_3.GetValueOrDefault();
    }

    foreach (var barcode in obj.IM_BARCOD) {
        product.Barcodes.Add(barcode.DIM_1_UPR, barcode.BARCOD);
    }

    foreach (var size in obj.IM_GRID_DIM_1) {
        product.Sizes.Add(ProductSize.FromEfObject(size));
    }

    foreach (var width in obj.IM_GRID_DIM_2) {
        product.Widths.Add(ProductSize.FromEfObject(width));
    }

    foreach (var length in obj.IM_GRID_DIM_3) {
        product.Lengths.Add(ProductSize.FromEfObject(length));
    }

    if (!product.Sizes.Any()) {
        product.Sizes.Add(new ProductSize());
    }

    if (!product.Widths.Any()) {
        product.Widths.Add(new ProductSize());
    }

    if (!product.Lengths.Any()) {
        product.Lengths.Add(new ProductSize());
    }

    return product;
}

And my method to retrieve the model: 我的方法来检索模型:

public ProductEntity GetProductById(string itemNumber, int storeNumber) {
    var product = _unitOfWork
        .GetProductRepository(storeNumber)
        .GetQueryable()
        .FirstOrDefault(p => p.ITEM_NO == itemNumber);

    return product == null ? null : ProductEntity.FromEfObject(product);
}

And the GetQueryable method: 和GetQueryable方法:

internal DbSet<TEntity> DbSet;
public GenericRepository(TContext context)
{
    Context = context;
    DbSet = context.Set<TEntity>();
}

public virtual IQueryable<TEntity> GetQueryable()
{
    IQueryable<TEntity> query = DbSet;
    return query;
}

A little more info.. I used database first modeling to create my data model, and the database I am testing against doesn't have a ton of data. 更多信息..我使用数据库优先建模来创建我的数据模型,我正在测试的数据库没有大量的数据。 Also, I tried using .Include() in my GetProductById method to load (eagerly I believe) but the slowed it down even further. 另外,我尝试在我的GetProductById方法中使用.Include()来加载(急切地相信)但是进一步放慢了速度。

Am I doing something fundamentally wrong? 我做了一些根本错误的事吗? Or is using EF going to be slow for a query like this. 或者使用EF对于这样的查询来说会很慢。

EDIT: To prevent lazy loading I updated my query to: 编辑:为了防止延迟加载我更新了我的查询:

    public ProductEntity GetProductById(string itemNumber, int storeNumber) {
        var product = _unitOfWork
            .GetProductRepository(storeNumber)
            .GetQueryable()
            .Include(p => p.IM_INV.Select(i => i.IM_INV_CELL))
            .Include(p => p.IM_BARCOD)
            .Include(p => p.IM_GRID_DIM_1)
            .Include(p => p.IM_GRID_DIM_2)
            .Include(p => p.IM_GRID_DIM_3)
            .Include(p => p.IM_PRC)
            .FirstOrDefault(p => p.ITEM_NO == itemNumber);

        return product == null ? null : ProductEntity.FromEfObject(product);
    }

When tracing, this gives me just one big nasty query that takes longer than using the lazy loading http://pastebin.com/LT1vTETb 在跟踪时,这给了我一个非常讨厌的查询,比使用延迟加载需要更长的时间http://pastebin.com/LT1vTETb

You can optimize your query to avoid lazy loading. 您可以优化查询以避免延迟加载。 In this case, when you load an object from the database, you know you're going to have to map almost the entire object graph to memory. 在这种情况下,当您从数据库加载对象时,您知道您将必须将几乎整个对象图映射到内存。 You're going to need to look up all of those foreign keys later anyway - it's faster to do it all as one query rather than letting lazy loading do the work. 无论如何,您将需要稍后查找所有这些外键 - 将所有这些作为一个查询更快,而不是让延迟加载完成工作。 See here for more information. 有关更多信息,请参见此处

It should look something like this: 它应该看起来像这样:

public ProductEntity GetProductById(string itemNumber, int storeNumber) {
    var product = _unitOfWork
        .GetProductRepository(storeNumber)
        .GetQueryable()
        .Include(p => p.IM_BARCOD)
        .Include(p => p.IM_GRID_DIM_1)
        .Include(p => p.IM_GRID_DIM_2)
        .Include(p => p.IM_GRID_DIM_3)
        .Include(p => p.IM_PRC)
        .FirstOrDefault(p => p.ITEM_NO == itemNumber);

    return product == null ? null : ProductEntity.FromEfObject(product);
}

Note that if these foreign keys have their own foreign keys (ie IM_BARCOD has a collection of IM_OtherType) which you also need to map to your ProductEntity model, you should also include those. 请注意,如果这些外键具有自己的外键(即IM_BARCOD具有IM_OtherType的集合),您还需要将其映射到ProductEntity模型,则还应包括这些外键。 You can do it in line like this: 你可以这样做:

.Include(p => p.IM_BARCOD.Select(b => b.IM_OTHERTYPE))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM