是否可以缩短EF6预热时间?

时间:2018-10-01 08:37:04

标签: entity-framework dbcontext

我有一个应用程序,在其中验证了以下行为:长时间不活动后的第一个请求会花费很长时间,有时会超时。 是否有可能控制实体框架如何管理对象的处置?是否可以将某些实体标记为永不处置? ...是为了避免/改善预热时间?

此致

1 个答案:

答案 0 :(得分:2)

相似查询将缩短响应时间的原因是多方面的。

  • 大多数数据库管理系统都会缓存部分获取的数据,因此在不久的将来类似的查询会更快。如果您确实查询Teachers with their Students,则Teachers表将与Students表联接。此连接结果通常会缓存一段时间。对Teachers with their Students的下一个查询将重用此联接结果,从而变得更快
  • DbContext缓存查询的对象。如果选择Single老师或Find老师,则该老师将保存在本地内存中。这样可以检测到在调用SaveChanges时更改了哪些项目。如果再次Find相同Teacher,则此查询会更快。如果您查询1000 Teachers,我不确定是否会发生同样的情况。
  • 创建DbContext对象时,将检查初始化程序以查看模型是否已更改。

因此,不Dispose()创建的DbContext似乎是明智的选择,但是您会看到大多数人在较短的时间内保持DbContext的生命:

using (var dbContext = new MyDbContext(...))
{
    var fetchedTeacher = dbContext.Teachers
        .Where(teacher => teacher.Id = ...)
        .Select(teacher => new
        {
            Id = teacher.Id,
            Name = teacher.Name,
            Students = teacher.Students.ToList(),
         })
         .FirstOrDefault();
    return fetchedTeacher;
}
// DbContext is Disposed()

乍一看,似乎最好保持DbContext的生命。如果有人要求相同的Teacher,则DbContext不必向数据库询问,它可以返回本地教师。

但是,保持DbContext有效可能会导致您获得错误的数据。如果其他人在您对此查询Teacher进行的第一次查询和第二次查询之间更改了Teacher,则会得到旧的Teacher数据。

因此,明智的做法是使DbContext的生存时间尽可能短。

我无法采取任何措施来提高第一个查询的速度吗?

可以!

您可以做的第一件事是设置数据库的初始化,以便它不检查数据库的存在和模型。当然,只有在完全确定数据库存在且未更改的情况下,您才能执行此操作。

// constructor; disables initializer
public SchoolDBContext() : base(...)
{            
    //Disable initializer
    Database.SetInitializer<SchoolDBContext>(null);
}

另一件事可能是,如果您已经获取了对象以更新数据库,并且确定没有其他人更改了该对象,则可以Attach使用它,而不用再次获取它,{{3 }}

常规用法:

// update the name of the teacher with teacherId
void ChangeTeacherName(int teacherId, string name)
{
    using (var dbContext = new SchoolContext(...))
    {
        // fetch the teacher, change the name and save
        Teacher fetchedTeacher = dbContext.Teachers.Find(teacherId);
        fetchedTeader.Name = name;
        dbContext.SaveChanges();
    }
}

使用Attach更新先前获取的教师:

void ChangeTeacherName (Teacher teacher, string name)
{
    using (var dbContext = new SchoolContext(...))
    {
          dbContext.Teachers.Attach(teacher);
          dbContext.Entry(teacher).Property(t => t.Name).IsModified = true;
          dbContext.SaveChanges();
    }
}

使用此方法不需要再次获取教师。在SaveChanges期间,将检查所有IsModified项目的所有属性Attached的值。如果需要,它们将被更新。