如何快速加载相关实体

时间:2014-12-10 11:47:10

标签: c# mysql entity-framework entity-framework-4 dbcontext

我想使用 DbContext / EntityFramework 加载Test ID,包括所有相关的TestRuns和所有Measurements来自MySql数据库。

这是数据库架构:

enter image description here

到目前为止我尝试了什么:

public class TestRepository : Repository<Test>, ITestRepository
{
    public IQueryable<Test> GetTestComplete(int id)
    {
      return DbSet.Where(t => t.Id == id)
                  .Include(t => t.TestRuns.Select(tr => tr.Measurements));
    }
}

不幸的是,这需要很长时间才能完成(1次测试/ 1次Testrun / 15000测量大约需要1分钟)。我试图通过使用查询分析器来理解生成的SQL代码,但无法理解巨大的怪物SQL语句。

你能想到使用DbContext加载数据的更好(即更快)的方法吗?


更新

另一次尝试,也导致加载时间过长:

public Test GetTestComplete(int id)
{
    Test test = DbSet.Find(id);
    DbContext.Entry(test).Collection(t => t.TestRuns).Load();
    foreach (var testRun in test.TestRuns)
    {
        // next line takes a lot of time!
        DbContext.Entry(testRun).Collection(tr=>tr.Measurements).Load(); 
    }
    return test;
}

加载测量值占84%的时间:

enter image description here

这是用于获取测量值的相应sql语句:

SELECT 
Extent1.id,
Extent1.test_run_id,
Extent1.rss_dbm
FROM measurement AS Extent1
WHERE Extent1.test_run_id = :EntityKeyValue1

我将每个生成的sql语句(来自三个DbContext / DbSet查询)从查询分析器复制到 MySqlWorkbench ,并且每个语句都运行得非常快。现在我更加困惑......


更新2

我在单个单元/性能测试中隔离了函数GetTestComplete(见上文),但仍需要很长时间。查询分析器的输出显示单个sql命令非常快,即使整个测试大约需要5秒钟才能完成。 混乱增长......

enter image description here

2 个答案:

答案 0 :(得分:2)

执行查询是一回事。 EF将非常快速地做到这一点。另一件事是实现实体对象,为更改跟踪器创建DbEntityEntry和关系对象。

如果您按...获取实体

DbSet.AsNoTracking()

...创建这些DbEntityEntry的过程会被取消,这通常会大大提高性能。

如果您应用AsNoTracking,则只能使用Include加载相关实体。像......这样的陈述。

DbContext.Entry(testRun).Collection(tr => tr.Measurements).Load();

...会失败,因为首先不会成为testRun的条目, Load方法与{ {1}},因为它旨在将跟踪的实体加载到上下文中而不返回它们。

答案 1 :(得分:-1)