实体框架在映射最多100k的数据时过慢

时间:2018-07-07 05:34:25

标签: entity-framework entity-framework-6

我在Job_Details表中至少有10万个数据,并且我正在使用Entity Framework映射数据。

这是代码:

public GetJobsResponse GetImportJobs()
{
    GetJobsResponse getJobResponse = new GetJobsResponse();
    List<JobBO> lstJobs = new List<JobBO>();

    using (NSEXIM_V2Entities dbContext = new NSEXIM_V2Entities())
    {
        var lstJob = dbContext.Job_Details.ToList();

        foreach (var dbJob in lstJob.Where(ie => ie.IMP_EXP == "I" && ie.Job_No != null))
        {
            JobBO job = MapBEJobforSearchObj(dbJob);
            lstJobs.Add(job);
        }
    }

    getJobResponse.Jobs = lstJobs;

    return getJobResponse;
}

我发现这一行执行大约需要2-3分钟

var lstJob = dbContext.Job_Details.ToList();

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

使用示例概述性能问题:(请参见内联注释)

public GetJobsResponse GetImportJobs()
{
    GetJobsResponse getJobResponse = new GetJobsResponse();
    List<JobBO> lstJobs = new List<JobBO>();

    using (NSEXIM_V2Entities dbContext = new NSEXIM_V2Entities())
    {
        // Loads *ALL* entities into memory. This effectively takes all fields for all rows across from the database to your app server. (Even though you don't want it all)
        var lstJob = dbContext.Job_Details.ToList(); 

        // Filters from the data in memory.
        foreach (var dbJob in lstJob.Where(ie => ie.IMP_EXP == "I" && ie.Job_No != null))
        {
        // Maps the entity to a DTO and adds it to the return collection.
            JobBO job = MapBEJobforSearchObj(dbJob);
            lstJobs.Add(job);
        }
    }
    // Returns the DTOs.
    getJobResponse.Jobs = lstJobs;

    return getJobResponse;
}

首先:将WHERE子句传递给EF,以传递给数据库服务器,而不是将所有实体加载到内存中。

public GetJobsResponse GetImportJobs()
{
    GetJobsResponse getJobResponse = new GetJobsResponse();

    using (NSEXIM_V2Entities dbContext = new NSEXIM_V2Entities())
    {
        // Will pass the where expression to be DB server to be executed. Note: No .ToList() yet to leave this as IQueryable.
        var jobs = dbContext.Job_Details..Where(ie => ie.IMP_EXP == "I" && ie.Job_No != null));

接下来,使用SELECT加载DTO。通常,这些数据所包含的数据不会像主要实体那样多,并且只要您使用IQueryable,就可以根据需要加载相关数据。同样,它将被发送到数据库服务器,因此您不能在此处使用“ MapBEJobForSearchObj”之类的功能,因为数据库服务器不知道该功能。您可以选择一个简单的DTO对象,也可以选择一个匿名类型来传递给动态映射器。

    var dtos = jobs.Select(ie => new JobBO
       {
          JobId = ie.JobId,
          // ... populate remaining DTO fields here.
       }).ToList();
    getJobResponse.Jobs = dtos;

    return getJobResponse;
}

将.ToList()移至末尾会将数据具体化到JobBO DTO / ViewModels中,仅从服务器提取足够的数据以填充所需的行和所需的字段。

在可能有大量数据的情况下,您还应该考虑支持服务器端分页,在其中传递页面编号和页面大小,然后利用.Skip()+ .Take()加载单个一次一页的条目。