实体框架 - 提高查询效率以检索大量数据

发布于 2025-01-31 06:25:12 字数 2315 浏览 3 评论 0原文

我有一个数据库,上面有很多数据 - Excel文件管理。

当每个对象包含一个excel文件时,该应用程序会管理对象(每张纸的数量,排行的列表)。

该应用程序包含一个数据网格和一张床单列表。用户将选出“修订号”和“表格”名称,显示同一表的行。

对象是这样构建的:

版本对象包含页面列表,每个页面都包含pageline列表。

检索数据的最佳方法是什么?

例如,我的PopulateGrid方法:

public void PopulateGrid() 
{
    CurrentPageLineGridObjects.Clear();
    PreviousPageLineGridObjects.Clear();
    SetCurrentConnectorPageList();

    // get current revision
    CurrentPageLineGridObjects = CurrentCombinedPageList.Where(page => page.Name == 
 PageNameSelected).FirstOrDefault().PageLines.ToList().ToObservablePageLineGridObjectCollection();
    //get prev revision
    RevisionCOMBINED prevRevCombined = pgroupDataService.GetRevisionCombinedForPGroup(((PGroup)PGroupSelected.Object).Id).Result;
    // get pages and pagelines for revision eeprom and override.
    List<Page> eepromPages =  
 revisionEEPROMDataService.GetEEPROMPages(prevRevCombined.RevisionEEPROM.Id).Result;                    
}

public async Task<List<Page>> GetEEPROMPages(int eepromRevId)
{
    string[] includes = { "Pages", "Pages.PageLines" };
    IEnumerable<RevisionEEPROM> list = (IEnumerable<RevisionEEPROM>)await dataService.GetAll(includes);
    return list.Where(r => r.Id == eepromRevId).SelectMany(p => p.Pages).ToList();
}

public async Task<IEnumerable<T>> GetAll()
{
    using (DeployToolDBContex contex = _contexFactory.CreateDbContext())
    {
        IEnumerable<T> entities = await contex.Set<T>().ToListAsync();
        return entities;
    }
}

如您所见,我将所有版本的数据以及所有床单和所有PAGELINE一起删除,然后才通过给定版本键进行过滤。

我花了很长时间才能加载。

感谢任何建议。

我尝试使用iQueryable

public async Task<List<T>> GetQueryable(string[] includes = null)
{
    using (DeployToolDBContex context = _contextFactory.CreateDbContext())
    {
        if (includes != null)
        {
            var query = context.Set<T>().AsQueryable();

            foreach (var include in includes)
                query = query.Include(include);

            return query.ToList();
        }
        else
        {
            List<T> entities = await context.Set<T>().AsQueryable().ToListAsync();
            return entities;
        }
    }
}

I have a database with lots of data - Excel file management.

The application manages objects when each object contains an Excel file (number of sheets, list of rows for each sheet).

The application contains a Data Grid and a list of sheets. The user will select revision number, and sheet name, the lines of the same sheet are displayed.

The objects are built like this:

Version object contains list of Pages, each page contains list of PageLine.

What is the best way to retrieve data ?

For example, my PopulateGrid method :

public void PopulateGrid() 
{
    CurrentPageLineGridObjects.Clear();
    PreviousPageLineGridObjects.Clear();
    SetCurrentConnectorPageList();

    // get current revision
    CurrentPageLineGridObjects = CurrentCombinedPageList.Where(page => page.Name == 
 PageNameSelected).FirstOrDefault().PageLines.ToList().ToObservablePageLineGridObjectCollection();
    //get prev revision
    RevisionCOMBINED prevRevCombined = pgroupDataService.GetRevisionCombinedForPGroup(((PGroup)PGroupSelected.Object).Id).Result;
    // get pages and pagelines for revision eeprom and override.
    List<Page> eepromPages =  
 revisionEEPROMDataService.GetEEPROMPages(prevRevCombined.RevisionEEPROM.Id).Result;                    
}

public async Task<List<Page>> GetEEPROMPages(int eepromRevId)
{
    string[] includes = { "Pages", "Pages.PageLines" };
    IEnumerable<RevisionEEPROM> list = (IEnumerable<RevisionEEPROM>)await dataService.GetAll(includes);
    return list.Where(r => r.Id == eepromRevId).SelectMany(p => p.Pages).ToList();
}

public async Task<IEnumerable<T>> GetAll()
{
    using (DeployToolDBContex contex = _contexFactory.CreateDbContext())
    {
        IEnumerable<T> entities = await contex.Set<T>().ToListAsync();
        return entities;
    }
}

As you can see I pull out all the version data along with all the Sheets and all the PageLines and only then filter by the given version key.

It takes me quite a while to load.

I would appreciate any advice.

I tried to use IQueryable:

public async Task<List<T>> GetQueryable(string[] includes = null)
{
    using (DeployToolDBContex context = _contextFactory.CreateDbContext())
    {
        if (includes != null)
        {
            var query = context.Set<T>().AsQueryable();

            foreach (var include in includes)
                query = query.Include(include);

            return query.ToList();
        }
        else
        {
            List<T> entities = await context.Set<T>().AsQueryable().ToListAsync();
            return entities;
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

可爱咩 2025-02-07 06:25:12

这是对EF的可怕用途。首先,这样的代码:

IEnumerable<RevisionEEPROM> list = (IEnumerable<RevisionEEPROM>)await dataService.GetAll(includes);
return list.Where(r => r.Id == eepromRevId).SelectMany(p => p.Pages).ToList();

您正在获取整个表格,并在过滤之前(基于传递的数组)(基于包含数组的包含数组)中的关联。

鉴于您是使用 block <代码>在该数据服务方法中范围内的dbcontext,最佳选择是引入getPages foreepromrevision()方法,以获取数据服务中给定ID的页面。您对此数据服务的通用实现应该是这些数据服务的基类,以便它们可以提供共同的功能,但可以扩展以支持特定案例以优化每个区域的查询。例如,如果您有:

public class DataService<T>
{
    public async Task<IEnumerable<T>> GetAll() {...}

    // ...
}

使用:使用以下方式扩展它:

public class EepromDataService : DataService<EEPROM>
{
    public async Task<IEnumerable<Page>> GetPagesForEepromRevision(int eepromRevId)
    {
        using (DeployToolDBContext context = _contexFactory.CreateDbContext())
        {
            var pages = await context.Set<EEPROM>()
                .Where(x => x.Id == eepromRevId)
                .SelectMany(x => x.Pages)
                .ToListAsync();
            return pages;
        }
    }
}

因此,如果您的调用代码正在创建类似var dataService = new DataService&lt; eeprom&gt;();此会更改为var dataService = var dataService = new Eepromdataservice = new Eepromdataservice = ();

前面提到的可用选项:

public IQueryable<T> GetQueryable()
{
    var query = _context.Set<T>().AsQueryable();
    return query;
}

然后,当您去获取数据时:

 var results = await dataService.GetQueryable()
     .Where(r => r.Id == eepromRevId)
     .SelectMany(r => r.Pages)
     .ToListAsync();
return results;

这需要一个工作模式,该单位将在消费者级别(例如:geteepRompages方法)或注入共享的依赖关系来范围内dbcontext(例如:GeteePrompages方法) dbContext都跨越了tolistasync以及数据服务的呼叫者。由于您的示例是使用 block使用范围内的dbcontext范围内的dbcontext,这可能是更大的更改。

总体而言,您需要查看对异步和同步呼叫的使用,因为其他做类似的方法:

RevisionCOMBINED prevRevCombined = pgroupDataService.GetRevisionCombinedForPGroup(((PGroup)PGroupSelected.Object).Id).Result;

仅呼叫.result是非常糟糕的练习。如果您需要从同步方法中调用异步调用,则有适当的方法可以做到这一点,并确保可能发生异常起泡。如有示例,请参见( C#?)如果代码不需要异步,则将其同步。 async不是银色的“更快”子弹,它用于使支持代码更加响应速度,只要该代码实际上是为了整个过程而写入async。 (即ASP.NET中的HTTP Web请求)

This is terrible use of EF. For a start, code like this:

IEnumerable<RevisionEEPROM> list = (IEnumerable<RevisionEEPROM>)await dataService.GetAll(includes);
return list.Where(r => r.Id == eepromRevId).SelectMany(p => p.Pages).ToList();

You are fetching the entire table and associated includes (based on that includes array passed) into memory before filtering.

Given you are scoping the DbContext within that data service method with a using block, the best option would be to introduce a GetPagesForEepromRevision() method to fetch the pages for a given ID in your data service. Your Generic implementation for this Data Service should be a base class for these data services so that they can provide common functionality, but can be extended to support specific cases to optimize queries for each area. For instance if you have:

public class DataService<T>
{
    public async Task<IEnumerable<T>> GetAll() {...}

    // ...
}

extend it using:

public class EepromDataService : DataService<EEPROM>
{
    public async Task<IEnumerable<Page>> GetPagesForEepromRevision(int eepromRevId)
    {
        using (DeployToolDBContext context = _contexFactory.CreateDbContext())
        {
            var pages = await context.Set<EEPROM>()
                .Where(x => x.Id == eepromRevId)
                .SelectMany(x => x.Pages)
                .ToListAsync();
            return pages;
        }
    }
}

So if your calling code was creating something like a var dataService = new DataService<EEPROM>(); this would change to var dataService = new EepromDataService();

The IQueryable option mentioned before:

public IQueryable<T> GetQueryable()
{
    var query = _context.Set<T>().AsQueryable();
    return query;
}

Then when you go to fetch your data:

 var results = await dataService.GetQueryable()
     .Where(r => r.Id == eepromRevId)
     .SelectMany(r => r.Pages)
     .ToListAsync();
return results;

This requires either a Unit of Work pattern which would scope the DbContext at the consumer level (eg: GetEEPROMPages method) or a shared dependency injected DbContext that spans both the caller where ToListAsync would be called as well as the data service. Since your example is scoping the DbContext inside the dataService with a using block that's probably a bigger change.

Overall you need to review your use of asynchronous vs. synchronous calls because other methods that do things like:

RevisionCOMBINED prevRevCombined = pgroupDataService.GetRevisionCombinedForPGroup(((PGroup)PGroupSelected.Object).Id).Result;

is very bad practice to just call .Result. If you need to call async calls from within a synchronous method then there are proper ways to do it and ensure things like exception bubbling can occur. For examples, see (How to call asynchronous method from synchronous method in C#?) If the code doesn't need to be asynchronous then leave it synchronous. async is not a silver "go faster" bullet, it is used to make supporting code more responsive so long as that code is actually written to leverage async the entire way. (I.e. HTTP Web requests in ASP.Net)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文