实体框架查询太慢了

时间:2016-06-28 14:41:05

标签: c# entity-framework

我是实体框架的新手,喜欢简单,但速度有些麻烦。我想我可能会错误地使用延迟加载,但很难绕过它。我已将数据模型层和业务实体层分开,并使用函数从我的数据模型中创建业务实体。在这个函数中,我迭代不同的嵌套实体来创建它们相应的模型。好吧,这里有足够的漫游代码:

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; }
}

业务实体创建方法:

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;
}

我的方法来检索模型:

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);
}

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;
}

更多信息..我使用数据库优先建模来创建我的数据模型,而我正在测试的数据库没有大量数据。另外,我尝试在我的.Include()方法中使用GetProductById来加载(急切地相信)但是进一步放慢了速度。

我做了一些根本错误的事吗?或者使用EF对于这样的查询来说会很慢。

编辑:为了防止延迟加载,我将查询更新为:

    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);
    }

在跟踪时,这给了我一个大讨厌的查询,比使用延迟加载需要更长的时间http://pastebin.com/LT1vTETb

1 个答案:

答案 0 :(得分:1)

您可以优化查询以避免延迟加载。在这种情况下,当您从数据库加载对象时,您知道您必须将几乎整个对象图映射到内存。您无论如何都需要稍后查找所有这些外键 - 将所有内容作为一个查询更快,而不是让延迟加载完成工作。有关详细信息,请参阅here

看起来应该是这样的:

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);
}

请注意,如果这些外键具有自己的外键(即IM_BARCOD具有IM_OtherType的集合),您还需要将其映射到ProductEntity模型,则还应包括这些外键。你可以这样做:

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